From de279f32b3c08638bfbd6965b966e464c5b46a5d Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Fri, 4 Feb 2011 12:53:06 +0100 Subject: [PATCH] Squashed 'Mono.Cecil/' content from commit 6668bdc git-subtree-dir: Mono.Cecil git-subtree-split: 6668bdcbeed78041ab9844efc223eabaa404d73d --- .gitignore | 7 + Mono.Cecil.Cil/Code.cs | 252 ++ Mono.Cecil.Cil/CodeReader.cs | 604 ++++ Mono.Cecil.Cil/CodeWriter.cs | 638 ++++ Mono.Cecil.Cil/Document.cs | 111 + Mono.Cecil.Cil/ExceptionHandler.cs | 95 + Mono.Cecil.Cil/ILProcessor.cs | 278 ++ Mono.Cecil.Cil/Instruction.cs | 321 ++ Mono.Cecil.Cil/MethodBody.cs | 230 ++ Mono.Cecil.Cil/OpCode.cs | 524 +++ Mono.Cecil.Cil/OpCodes.cs | 912 +++++ Mono.Cecil.Cil/SequencePoint.cs | 70 + Mono.Cecil.Cil/Symbols.cs | 272 ++ Mono.Cecil.Cil/VariableDefinition.cs | 52 + Mono.Cecil.Cil/VariableReference.cs | 75 + Mono.Cecil.Metadata/BlobHeap.cs | 59 + Mono.Cecil.Metadata/Buffers.cs | 373 ++ Mono.Cecil.Metadata/CodedIndex.cs | 46 + Mono.Cecil.Metadata/ElementType.cs | 73 + Mono.Cecil.Metadata/GuidHeap.cs | 59 + Mono.Cecil.Metadata/Heap.cs | 48 + Mono.Cecil.Metadata/MetadataToken.cs | 105 + Mono.Cecil.Metadata/Row.cs | 170 + Mono.Cecil.Metadata/StringHeap.cs | 81 + Mono.Cecil.Metadata/TableHeap.cs | 153 + Mono.Cecil.Metadata/TokenType.cs | 56 + Mono.Cecil.Metadata/UserStringHeap.cs | 59 + Mono.Cecil.Metadata/Utilities.cs | 529 +++ Mono.Cecil.PE/BinaryStreamReader.cs | 51 + Mono.Cecil.PE/BinaryStreamWriter.cs | 96 + Mono.Cecil.PE/ByteBuffer.cs | 342 ++ Mono.Cecil.PE/ByteBufferEqualityComparer.cs | 78 + Mono.Cecil.PE/DataDirectory.cs | 50 + Mono.Cecil.PE/Image.cs | 159 + Mono.Cecil.PE/ImageReader.cs | 678 ++++ Mono.Cecil.PE/ImageWriter.cs | 820 +++++ Mono.Cecil.PE/Section.cs | 43 + Mono.Cecil.PE/TextMap.cs | 129 + Mono.Cecil.csproj | 264 ++ Mono.Cecil.nunit | 9 + Mono.Cecil.sln | 197 ++ Mono.Cecil/ArrayType.cs | 159 + Mono.Cecil/AssemblyDefinition.cs | 189 + Mono.Cecil/AssemblyFlags.cs | 41 + Mono.Cecil/AssemblyHashAlgorithm.cs | 36 + Mono.Cecil/AssemblyInfo.cs | 49 + Mono.Cecil/AssemblyLinkedResource.cs | 57 + Mono.Cecil/AssemblyNameDefinition.cs | 50 + Mono.Cecil/AssemblyNameReference.cs | 263 ++ Mono.Cecil/AssemblyReader.cs | 3047 +++++++++++++++++ Mono.Cecil/AssemblyWriter.cs | 2536 ++++++++++++++ Mono.Cecil/BaseAssemblyResolver.cs | 336 ++ Mono.Cecil/CallSite.cs | 54 + Mono.Cecil/CustomAttribute.cs | 232 ++ Mono.Cecil/DefaultAssemblyResolver.cs | 75 + Mono.Cecil/EmbeddedResource.cs | 105 + Mono.Cecil/EventAttributes.cs | 39 + Mono.Cecil/EventDefinition.cs | 168 + Mono.Cecil/EventReference.cs | 57 + Mono.Cecil/ExportedType.cs | 249 ++ Mono.Cecil/FieldAttributes.cs | 59 + Mono.Cecil/FieldDefinition.cs | 279 ++ Mono.Cecil/FieldReference.cs | 83 + Mono.Cecil/FileAttributes.cs | 35 + Mono.Cecil/FunctionPointerType.cs | 128 + Mono.Cecil/GenericInstanceMethod.cs | 90 + Mono.Cecil/GenericInstanceType.cs | 88 + Mono.Cecil/GenericParameter.cs | 201 ++ Mono.Cecil/GenericParameterAttributes.cs | 45 + Mono.Cecil/IConstantProvider.cs | 52 + Mono.Cecil/ICustomAttributeProvider.cs | 62 + Mono.Cecil/IGenericInstance.cs | 66 + Mono.Cecil/IGenericParameterProvider.cs | 75 + Mono.Cecil/IMarshalInfoProvider.cs | 57 + Mono.Cecil/IMemberDefinition.cs | 100 + Mono.Cecil/IMetadataScope.cs | 41 + Mono.Cecil/IMetadataTokenProvider.cs | 35 + Mono.Cecil/IMethodSignature.cs | 70 + Mono.Cecil/Import.cs | 566 +++ Mono.Cecil/LinkedResource.cs | 60 + Mono.Cecil/ManifestResourceAttributes.cs | 39 + Mono.Cecil/MarshalInfo.cs | 171 + Mono.Cecil/MemberDefinitionCollection.cs | 92 + Mono.Cecil/MemberReference.cs | 101 + Mono.Cecil/MetadataResolver.cs | 313 ++ Mono.Cecil/MetadataSystem.cs | 380 ++ Mono.Cecil/MethodAttributes.cs | 66 + Mono.Cecil/MethodCallingConvention.cs | 40 + Mono.Cecil/MethodDefinition.cs | 487 +++ Mono.Cecil/MethodImplAttributes.cs | 54 + Mono.Cecil/MethodReference.cs | 214 ++ Mono.Cecil/MethodReturnType.cs | 100 + Mono.Cecil/MethodSemanticsAttributes.cs | 43 + Mono.Cecil/MethodSpecification.cs | 103 + Mono.Cecil/Modifiers.cs | 137 + Mono.Cecil/ModuleDefinition.cs | 965 ++++++ Mono.Cecil/ModuleKind.cs | 52 + Mono.Cecil/ModuleReference.cs | 67 + Mono.Cecil/NativeType.cs | 73 + Mono.Cecil/PInvokeAttributes.cs | 62 + Mono.Cecil/PInvokeInfo.cs | 138 + Mono.Cecil/ParameterAttributes.cs | 45 + Mono.Cecil/ParameterDefinition.cs | 157 + Mono.Cecil/ParameterDefinitionCollection.cs | 80 + Mono.Cecil/ParameterReference.cs | 75 + Mono.Cecil/PinnedType.cs | 53 + Mono.Cecil/PointerType.cs | 61 + Mono.Cecil/PropertyAttributes.cs | 41 + Mono.Cecil/PropertyDefinition.cs | 263 ++ Mono.Cecil/PropertyReference.cs | 59 + Mono.Cecil/ReferenceType.cs | 61 + Mono.Cecil/Resource.cs | 76 + Mono.Cecil/SecurityDeclaration.cs | 182 + Mono.Cecil/SentinelType.cs | 53 + Mono.Cecil/TargetRuntime.cs | 37 + Mono.Cecil/TypeAttributes.cs | 80 + Mono.Cecil/TypeDefinition.cs | 499 +++ Mono.Cecil/TypeDefinitionCollection.cs | 118 + Mono.Cecil/TypeParser.cs | 555 +++ Mono.Cecil/TypeReference.cs | 327 ++ Mono.Cecil/TypeSpecification.cs | 94 + Mono.Cecil/TypeSystem.cs | 273 ++ Mono.Cecil/VariantType.cs | 53 + Mono.Collections.Generic/Collection.cs | 417 +++ .../ReadOnlyCollection.cs | 103 + Mono.Security.Cryptography/CryptoConvert.cs | 243 ++ Mono.Security.Cryptography/CryptoService.cs | 177 + Mono/Actions.cs | 38 + Mono/Empty.cs | 55 + Mono/Funcs.cs | 39 + NOTES.txt | 189 + .../ExtensionAttribute.cs | 40 + Test/.gitignore | 7 + Test/Mono.Cecil.Tests.csproj | 171 + Test/Mono.Cecil.Tests/Addin.cs | 303 ++ Test/Mono.Cecil.Tests/AssemblyInfo.cs | 14 + Test/Mono.Cecil.Tests/AssemblyTests.cs | 25 + Test/Mono.Cecil.Tests/BaseTestFixture.cs | 76 + Test/Mono.Cecil.Tests/CompilationService.cs | 237 ++ .../Mono.Cecil.Tests/CustomAttributesTests.cs | 511 +++ Test/Mono.Cecil.Tests/EventTests.cs | 66 + Test/Mono.Cecil.Tests/Extensions.cs | 92 + Test/Mono.Cecil.Tests/FieldTests.cs | 324 ++ Test/Mono.Cecil.Tests/Formatter.cs | 173 + Test/Mono.Cecil.Tests/ILProcessorTests.cs | 79 + Test/Mono.Cecil.Tests/ImageReadTests.cs | 127 + Test/Mono.Cecil.Tests/ImportCecilTests.cs | 310 ++ .../Mono.Cecil.Tests/ImportReflectionTests.cs | 409 +++ Test/Mono.Cecil.Tests/Linq.cs | 47 + Test/Mono.Cecil.Tests/MethodBodyTests.cs | 363 ++ Test/Mono.Cecil.Tests/MethodTests.cs | 193 ++ Test/Mono.Cecil.Tests/ModuleTests.cs | 240 ++ Test/Mono.Cecil.Tests/NestedTypesTests.cs | 45 + Test/Mono.Cecil.Tests/ParameterTests.cs | 224 ++ Test/Mono.Cecil.Tests/PropertyTests.cs | 112 + Test/Mono.Cecil.Tests/ResolveTests.cs | 262 ++ .../SecurityDeclarationTests.cs | 199 ++ Test/Mono.Cecil.Tests/TypeParserTests.cs | 394 +++ Test/Mono.Cecil.Tests/TypeTests.cs | 171 + Test/Mono.Cecil.Tests/VariableTests.cs | 108 + Test/Resources/assemblies/boxedoptarg.dll | Bin 0 -> 3072 bytes Test/Resources/assemblies/catch.exe | Bin 0 -> 3584 bytes Test/Resources/assemblies/cppcli.dll | Bin 0 -> 50176 bytes Test/Resources/assemblies/decsec-att.dll | Bin 0 -> 4096 bytes Test/Resources/assemblies/decsec-xml.dll | Bin 0 -> 5120 bytes Test/Resources/assemblies/fptr.exe | Bin 0 -> 2048 bytes Test/Resources/assemblies/gifaceref.exe | Bin 0 -> 5120 bytes Test/Resources/assemblies/hello.anycpu.exe | Bin 0 -> 3584 bytes Test/Resources/assemblies/hello.exe | Bin 0 -> 3584 bytes Test/Resources/assemblies/hello.ia64.exe | Bin 0 -> 3072 bytes Test/Resources/assemblies/hello.x64.exe | Bin 0 -> 3072 bytes Test/Resources/assemblies/hello.x86.exe | Bin 0 -> 3584 bytes Test/Resources/assemblies/hello1.exe | Bin 0 -> 3072 bytes Test/Resources/assemblies/hellow.exe | Bin 0 -> 3584 bytes Test/Resources/assemblies/iterator.exe | Bin 0 -> 5632 bytes Test/Resources/assemblies/libhello.dll | Bin 0 -> 3072 bytes Test/Resources/assemblies/libres.dll | Bin 0 -> 3072 bytes Test/Resources/assemblies/marshal.dll | Bin 0 -> 3584 bytes Test/Resources/assemblies/mma.exe | Bin 0 -> 3584 bytes Test/Resources/assemblies/moda.netmodule | Bin 0 -> 2048 bytes Test/Resources/assemblies/modb.netmodule | Bin 0 -> 2048 bytes Test/Resources/assemblies/noblob.dll | Bin 0 -> 3072 bytes Test/Resources/assemblies/pinvoke.exe | Bin 0 -> 4096 bytes Test/Resources/assemblies/switch.exe | Bin 0 -> 3584 bytes Test/Resources/assemblies/text_file.txt | 1 + Test/Resources/assemblies/varargs.exe | Bin 0 -> 2048 bytes Test/Resources/cs/CustomAttributes.cs | 152 + Test/Resources/cs/Events.cs | 8 + Test/Resources/cs/Fields.cs | 41 + Test/Resources/cs/Generics.cs | 114 + Test/Resources/cs/Interfaces.cs | 22 + Test/Resources/cs/Layouts.cs | 16 + Test/Resources/cs/Methods.cs | 21 + Test/Resources/cs/NestedTypes.cs | 16 + Test/Resources/cs/Properties.cs | 18 + Test/Resources/il/hello.il | 84 + Test/Resources/il/methodspecs.il | 43 + Test/Resources/il/others.il | 81 + Test/Resources/il/types.il | 46 + Test/libs/nunit-2.4.8/license.txt | 15 + Test/libs/nunit-2.4.8/nunit.core.dll | Bin 0 -> 90112 bytes .../nunit-2.4.8/nunit.core.interfaces.dll | Bin 0 -> 40960 bytes Test/libs/nunit-2.4.8/nunit.framework.dll | Bin 0 -> 77824 bytes dbg/Program.cs | 60 + dbg/Properties/AssemblyInfo.cs | 36 + dbg/dbg.csproj | 85 + mono.snk | Bin 0 -> 596 bytes rocks/.gitignore | 7 + rocks/Mono.Cecil.Rocks.csproj | 129 + rocks/Mono.Cecil.Rocks/AssemblyInfo.cs | 41 + rocks/Mono.Cecil.Rocks/Functional.cs | 59 + rocks/Mono.Cecil.Rocks/ILParser.cs | 236 ++ rocks/Mono.Cecil.Rocks/MethodBodyRocks.cs | 407 +++ .../Mono.Cecil.Rocks/MethodDefinitionRocks.cs | 88 + .../Mono.Cecil.Rocks/ModuleDefinitionRocks.cs | 50 + .../ParameterReferenceRocks.cs | 11 + .../SecurityDeclarationRocks.cs | 174 + rocks/Mono.Cecil.Rocks/TypeDefinitionRocks.cs | 83 + rocks/Mono.Cecil.Rocks/TypeReferenceRocks.cs | 107 + rocks/Test/.gitignore | 7 + rocks/Test/Mono.Cecil.Rocks.Tests.csproj | 106 + rocks/Test/Mono.Cecil.Tests/Addin.cs | 8 + .../MethodDefinitionRocksTests.cs | 53 + .../ModuleDefinitionRocksTests.cs | 27 + .../SecurityDeclarationRocksTests.cs | 63 + .../TypeDefinitionRocksTests.cs | 97 + .../TypeReferenceRocksTests.cs | 124 + .../Test/Resources/assemblies/decsec-att.dll | Bin 0 -> 4096 bytes .../Test/Resources/assemblies/decsec-xml.dll | Bin 0 -> 5120 bytes rocks/Test/Resources/cs/Types.cs | 14 + symbols/mdb/.gitignore | 4 + symbols/mdb/Mono.Cecil.Mdb.csproj | 103 + symbols/mdb/Mono.Cecil.Mdb/AssemblyInfo.cs | 41 + symbols/mdb/Mono.Cecil.Mdb/MdbReader.cs | 213 ++ symbols/mdb/Mono.Cecil.Mdb/MdbWriter.cs | 251 ++ .../MonoSymbolFile.cs | 733 ++++ .../MonoSymbolTable.cs | 1376 ++++++++ .../MonoSymbolWriter.cs | 403 +++ .../SymbolWriterImpl.cs | 349 ++ symbols/mdb/Test/.gitignore | 4 + symbols/mdb/Test/Mono.Cecil.Mdb.Tests.csproj | 119 + symbols/mdb/Test/Mono.Cecil.Tests/Addin.cs | 8 + symbols/mdb/Test/Mono.Cecil.Tests/MdbTests.cs | 58 + .../mdb/Test/Resources/assemblies/hello.exe | Bin 0 -> 3072 bytes .../Test/Resources/assemblies/hello.exe.mdb | Bin 0 -> 369 bytes symbols/pdb/.gitignore | 4 + symbols/pdb/Microsoft.Cci.Pdb/BitAccess.cs | 229 ++ symbols/pdb/Microsoft.Cci.Pdb/BitSet.cs | 69 + symbols/pdb/Microsoft.Cci.Pdb/CvInfo.cs | 2430 +++++++++++++ symbols/pdb/Microsoft.Cci.Pdb/DataStream.cs | 146 + symbols/pdb/Microsoft.Cci.Pdb/DbiDbgHdr.cs | 36 + symbols/pdb/Microsoft.Cci.Pdb/DbiHeader.cs | 54 + .../pdb/Microsoft.Cci.Pdb/DbiModuleInfo.cs | 52 + symbols/pdb/Microsoft.Cci.Pdb/DbiSecCon.cs | 37 + symbols/pdb/Microsoft.Cci.Pdb/IntHashTable.cs | 579 ++++ symbols/pdb/Microsoft.Cci.Pdb/Interfaces.cs | 77 + symbols/pdb/Microsoft.Cci.Pdb/LICENSE | 22 + symbols/pdb/Microsoft.Cci.Pdb/MsfDirectory.cs | 45 + symbols/pdb/Microsoft.Cci.Pdb/PdbConstant.cs | 79 + .../Microsoft.Cci.Pdb/PdbDebugException.cs | 15 + symbols/pdb/Microsoft.Cci.Pdb/PdbException.cs | 15 + symbols/pdb/Microsoft.Cci.Pdb/PdbFile.cs | 421 +++ .../pdb/Microsoft.Cci.Pdb/PdbFileHeader.cs | 82 + symbols/pdb/Microsoft.Cci.Pdb/PdbFunction.cs | 399 +++ symbols/pdb/Microsoft.Cci.Pdb/PdbLine.cs | 24 + symbols/pdb/Microsoft.Cci.Pdb/PdbLines.cs | 18 + symbols/pdb/Microsoft.Cci.Pdb/PdbReader.cs | 35 + symbols/pdb/Microsoft.Cci.Pdb/PdbScope.cs | 104 + symbols/pdb/Microsoft.Cci.Pdb/PdbSlot.cs | 35 + symbols/pdb/Microsoft.Cci.Pdb/PdbSource.cs | 24 + symbols/pdb/Microsoft.Cci.Pdb/PdbWriter.cs | 129 + .../SourceLocationProvider.cs | 66 + symbols/pdb/Mono.Cecil.Pdb.csproj | 130 + symbols/pdb/Mono.Cecil.Pdb/AssemblyInfo.cs | 41 + .../ISymUnmanagedDocumentWriter.cs | 41 + .../Mono.Cecil.Pdb/ISymUnmanagedWriter2.cs | 103 + symbols/pdb/Mono.Cecil.Pdb/ModuleMetadata.cs | 715 ++++ symbols/pdb/Mono.Cecil.Pdb/PdbHelper.cs | 205 ++ symbols/pdb/Mono.Cecil.Pdb/PdbReader.cs | 282 ++ symbols/pdb/Mono.Cecil.Pdb/PdbWriter.cs | 222 ++ .../pdb/Mono.Cecil.Pdb/SymDocumentWriter.cs | 51 + symbols/pdb/Mono.Cecil.Pdb/SymWriter.cs | 170 + symbols/pdb/Test/.gitignore | 4 + symbols/pdb/Test/Mono.Cecil.Pdb.Tests.csproj | 120 + symbols/pdb/Test/Mono.Cecil.Tests/Addin.cs | 8 + symbols/pdb/Test/Mono.Cecil.Tests/Linq.cs | 47 + symbols/pdb/Test/Mono.Cecil.Tests/PdbTests.cs | 139 + .../pdb/Test/Resources/assemblies/test.exe | Bin 0 -> 4096 bytes .../pdb/Test/Resources/assemblies/test.pdb | Bin 0 -> 11776 bytes 289 files changed, 46540 insertions(+) create mode 100644 .gitignore create mode 100644 Mono.Cecil.Cil/Code.cs create mode 100644 Mono.Cecil.Cil/CodeReader.cs create mode 100644 Mono.Cecil.Cil/CodeWriter.cs create mode 100644 Mono.Cecil.Cil/Document.cs create mode 100644 Mono.Cecil.Cil/ExceptionHandler.cs create mode 100644 Mono.Cecil.Cil/ILProcessor.cs create mode 100644 Mono.Cecil.Cil/Instruction.cs create mode 100644 Mono.Cecil.Cil/MethodBody.cs create mode 100644 Mono.Cecil.Cil/OpCode.cs create mode 100644 Mono.Cecil.Cil/OpCodes.cs create mode 100644 Mono.Cecil.Cil/SequencePoint.cs create mode 100644 Mono.Cecil.Cil/Symbols.cs create mode 100644 Mono.Cecil.Cil/VariableDefinition.cs create mode 100644 Mono.Cecil.Cil/VariableReference.cs create mode 100644 Mono.Cecil.Metadata/BlobHeap.cs create mode 100644 Mono.Cecil.Metadata/Buffers.cs create mode 100644 Mono.Cecil.Metadata/CodedIndex.cs create mode 100644 Mono.Cecil.Metadata/ElementType.cs create mode 100644 Mono.Cecil.Metadata/GuidHeap.cs create mode 100644 Mono.Cecil.Metadata/Heap.cs create mode 100644 Mono.Cecil.Metadata/MetadataToken.cs create mode 100644 Mono.Cecil.Metadata/Row.cs create mode 100644 Mono.Cecil.Metadata/StringHeap.cs create mode 100644 Mono.Cecil.Metadata/TableHeap.cs create mode 100644 Mono.Cecil.Metadata/TokenType.cs create mode 100644 Mono.Cecil.Metadata/UserStringHeap.cs create mode 100644 Mono.Cecil.Metadata/Utilities.cs create mode 100644 Mono.Cecil.PE/BinaryStreamReader.cs create mode 100644 Mono.Cecil.PE/BinaryStreamWriter.cs create mode 100644 Mono.Cecil.PE/ByteBuffer.cs create mode 100644 Mono.Cecil.PE/ByteBufferEqualityComparer.cs create mode 100644 Mono.Cecil.PE/DataDirectory.cs create mode 100644 Mono.Cecil.PE/Image.cs create mode 100644 Mono.Cecil.PE/ImageReader.cs create mode 100644 Mono.Cecil.PE/ImageWriter.cs create mode 100644 Mono.Cecil.PE/Section.cs create mode 100644 Mono.Cecil.PE/TextMap.cs create mode 100644 Mono.Cecil.csproj create mode 100755 Mono.Cecil.nunit create mode 100644 Mono.Cecil.sln create mode 100644 Mono.Cecil/ArrayType.cs create mode 100644 Mono.Cecil/AssemblyDefinition.cs create mode 100644 Mono.Cecil/AssemblyFlags.cs create mode 100644 Mono.Cecil/AssemblyHashAlgorithm.cs create mode 100644 Mono.Cecil/AssemblyInfo.cs create mode 100644 Mono.Cecil/AssemblyLinkedResource.cs create mode 100644 Mono.Cecil/AssemblyNameDefinition.cs create mode 100644 Mono.Cecil/AssemblyNameReference.cs create mode 100644 Mono.Cecil/AssemblyReader.cs create mode 100644 Mono.Cecil/AssemblyWriter.cs create mode 100644 Mono.Cecil/BaseAssemblyResolver.cs create mode 100644 Mono.Cecil/CallSite.cs create mode 100644 Mono.Cecil/CustomAttribute.cs create mode 100644 Mono.Cecil/DefaultAssemblyResolver.cs create mode 100644 Mono.Cecil/EmbeddedResource.cs create mode 100644 Mono.Cecil/EventAttributes.cs create mode 100644 Mono.Cecil/EventDefinition.cs create mode 100644 Mono.Cecil/EventReference.cs create mode 100644 Mono.Cecil/ExportedType.cs create mode 100644 Mono.Cecil/FieldAttributes.cs create mode 100644 Mono.Cecil/FieldDefinition.cs create mode 100644 Mono.Cecil/FieldReference.cs create mode 100644 Mono.Cecil/FileAttributes.cs create mode 100644 Mono.Cecil/FunctionPointerType.cs create mode 100644 Mono.Cecil/GenericInstanceMethod.cs create mode 100644 Mono.Cecil/GenericInstanceType.cs create mode 100644 Mono.Cecil/GenericParameter.cs create mode 100644 Mono.Cecil/GenericParameterAttributes.cs create mode 100644 Mono.Cecil/IConstantProvider.cs create mode 100644 Mono.Cecil/ICustomAttributeProvider.cs create mode 100644 Mono.Cecil/IGenericInstance.cs create mode 100644 Mono.Cecil/IGenericParameterProvider.cs create mode 100644 Mono.Cecil/IMarshalInfoProvider.cs create mode 100644 Mono.Cecil/IMemberDefinition.cs create mode 100644 Mono.Cecil/IMetadataScope.cs create mode 100644 Mono.Cecil/IMetadataTokenProvider.cs create mode 100644 Mono.Cecil/IMethodSignature.cs create mode 100644 Mono.Cecil/Import.cs create mode 100644 Mono.Cecil/LinkedResource.cs create mode 100644 Mono.Cecil/ManifestResourceAttributes.cs create mode 100644 Mono.Cecil/MarshalInfo.cs create mode 100644 Mono.Cecil/MemberDefinitionCollection.cs create mode 100644 Mono.Cecil/MemberReference.cs create mode 100644 Mono.Cecil/MetadataResolver.cs create mode 100644 Mono.Cecil/MetadataSystem.cs create mode 100644 Mono.Cecil/MethodAttributes.cs create mode 100644 Mono.Cecil/MethodCallingConvention.cs create mode 100644 Mono.Cecil/MethodDefinition.cs create mode 100644 Mono.Cecil/MethodImplAttributes.cs create mode 100644 Mono.Cecil/MethodReference.cs create mode 100644 Mono.Cecil/MethodReturnType.cs create mode 100644 Mono.Cecil/MethodSemanticsAttributes.cs create mode 100644 Mono.Cecil/MethodSpecification.cs create mode 100644 Mono.Cecil/Modifiers.cs create mode 100644 Mono.Cecil/ModuleDefinition.cs create mode 100644 Mono.Cecil/ModuleKind.cs create mode 100644 Mono.Cecil/ModuleReference.cs create mode 100644 Mono.Cecil/NativeType.cs create mode 100644 Mono.Cecil/PInvokeAttributes.cs create mode 100644 Mono.Cecil/PInvokeInfo.cs create mode 100644 Mono.Cecil/ParameterAttributes.cs create mode 100644 Mono.Cecil/ParameterDefinition.cs create mode 100644 Mono.Cecil/ParameterDefinitionCollection.cs create mode 100644 Mono.Cecil/ParameterReference.cs create mode 100644 Mono.Cecil/PinnedType.cs create mode 100644 Mono.Cecil/PointerType.cs create mode 100644 Mono.Cecil/PropertyAttributes.cs create mode 100644 Mono.Cecil/PropertyDefinition.cs create mode 100644 Mono.Cecil/PropertyReference.cs create mode 100644 Mono.Cecil/ReferenceType.cs create mode 100644 Mono.Cecil/Resource.cs create mode 100644 Mono.Cecil/SecurityDeclaration.cs create mode 100644 Mono.Cecil/SentinelType.cs create mode 100644 Mono.Cecil/TargetRuntime.cs create mode 100644 Mono.Cecil/TypeAttributes.cs create mode 100644 Mono.Cecil/TypeDefinition.cs create mode 100644 Mono.Cecil/TypeDefinitionCollection.cs create mode 100644 Mono.Cecil/TypeParser.cs create mode 100644 Mono.Cecil/TypeReference.cs create mode 100644 Mono.Cecil/TypeSpecification.cs create mode 100644 Mono.Cecil/TypeSystem.cs create mode 100644 Mono.Cecil/VariantType.cs create mode 100644 Mono.Collections.Generic/Collection.cs create mode 100644 Mono.Collections.Generic/ReadOnlyCollection.cs create mode 100644 Mono.Security.Cryptography/CryptoConvert.cs create mode 100644 Mono.Security.Cryptography/CryptoService.cs create mode 100644 Mono/Actions.cs create mode 100644 Mono/Empty.cs create mode 100644 Mono/Funcs.cs create mode 100644 NOTES.txt create mode 100644 System.Runtime.CompilerServices/ExtensionAttribute.cs create mode 100644 Test/.gitignore create mode 100644 Test/Mono.Cecil.Tests.csproj create mode 100644 Test/Mono.Cecil.Tests/Addin.cs create mode 100644 Test/Mono.Cecil.Tests/AssemblyInfo.cs create mode 100644 Test/Mono.Cecil.Tests/AssemblyTests.cs create mode 100644 Test/Mono.Cecil.Tests/BaseTestFixture.cs create mode 100644 Test/Mono.Cecil.Tests/CompilationService.cs create mode 100644 Test/Mono.Cecil.Tests/CustomAttributesTests.cs create mode 100644 Test/Mono.Cecil.Tests/EventTests.cs create mode 100644 Test/Mono.Cecil.Tests/Extensions.cs create mode 100644 Test/Mono.Cecil.Tests/FieldTests.cs create mode 100644 Test/Mono.Cecil.Tests/Formatter.cs create mode 100644 Test/Mono.Cecil.Tests/ILProcessorTests.cs create mode 100644 Test/Mono.Cecil.Tests/ImageReadTests.cs create mode 100644 Test/Mono.Cecil.Tests/ImportCecilTests.cs create mode 100644 Test/Mono.Cecil.Tests/ImportReflectionTests.cs create mode 100644 Test/Mono.Cecil.Tests/Linq.cs create mode 100644 Test/Mono.Cecil.Tests/MethodBodyTests.cs create mode 100644 Test/Mono.Cecil.Tests/MethodTests.cs create mode 100644 Test/Mono.Cecil.Tests/ModuleTests.cs create mode 100644 Test/Mono.Cecil.Tests/NestedTypesTests.cs create mode 100644 Test/Mono.Cecil.Tests/ParameterTests.cs create mode 100644 Test/Mono.Cecil.Tests/PropertyTests.cs create mode 100644 Test/Mono.Cecil.Tests/ResolveTests.cs create mode 100644 Test/Mono.Cecil.Tests/SecurityDeclarationTests.cs create mode 100644 Test/Mono.Cecil.Tests/TypeParserTests.cs create mode 100644 Test/Mono.Cecil.Tests/TypeTests.cs create mode 100644 Test/Mono.Cecil.Tests/VariableTests.cs create mode 100644 Test/Resources/assemblies/boxedoptarg.dll create mode 100644 Test/Resources/assemblies/catch.exe create mode 100644 Test/Resources/assemblies/cppcli.dll create mode 100644 Test/Resources/assemblies/decsec-att.dll create mode 100644 Test/Resources/assemblies/decsec-xml.dll create mode 100644 Test/Resources/assemblies/fptr.exe create mode 100644 Test/Resources/assemblies/gifaceref.exe create mode 100644 Test/Resources/assemblies/hello.anycpu.exe create mode 100644 Test/Resources/assemblies/hello.exe create mode 100644 Test/Resources/assemblies/hello.ia64.exe create mode 100644 Test/Resources/assemblies/hello.x64.exe create mode 100644 Test/Resources/assemblies/hello.x86.exe create mode 100644 Test/Resources/assemblies/hello1.exe create mode 100644 Test/Resources/assemblies/hellow.exe create mode 100644 Test/Resources/assemblies/iterator.exe create mode 100644 Test/Resources/assemblies/libhello.dll create mode 100644 Test/Resources/assemblies/libres.dll create mode 100644 Test/Resources/assemblies/marshal.dll create mode 100644 Test/Resources/assemblies/mma.exe create mode 100644 Test/Resources/assemblies/moda.netmodule create mode 100644 Test/Resources/assemblies/modb.netmodule create mode 100644 Test/Resources/assemblies/noblob.dll create mode 100644 Test/Resources/assemblies/pinvoke.exe create mode 100644 Test/Resources/assemblies/switch.exe create mode 100644 Test/Resources/assemblies/text_file.txt create mode 100644 Test/Resources/assemblies/varargs.exe create mode 100644 Test/Resources/cs/CustomAttributes.cs create mode 100644 Test/Resources/cs/Events.cs create mode 100644 Test/Resources/cs/Fields.cs create mode 100644 Test/Resources/cs/Generics.cs create mode 100644 Test/Resources/cs/Interfaces.cs create mode 100644 Test/Resources/cs/Layouts.cs create mode 100644 Test/Resources/cs/Methods.cs create mode 100644 Test/Resources/cs/NestedTypes.cs create mode 100644 Test/Resources/cs/Properties.cs create mode 100644 Test/Resources/il/hello.il create mode 100644 Test/Resources/il/methodspecs.il create mode 100644 Test/Resources/il/others.il create mode 100644 Test/Resources/il/types.il create mode 100644 Test/libs/nunit-2.4.8/license.txt create mode 100755 Test/libs/nunit-2.4.8/nunit.core.dll create mode 100755 Test/libs/nunit-2.4.8/nunit.core.interfaces.dll create mode 100755 Test/libs/nunit-2.4.8/nunit.framework.dll create mode 100644 dbg/Program.cs create mode 100644 dbg/Properties/AssemblyInfo.cs create mode 100644 dbg/dbg.csproj create mode 100644 mono.snk create mode 100644 rocks/.gitignore create mode 100644 rocks/Mono.Cecil.Rocks.csproj create mode 100644 rocks/Mono.Cecil.Rocks/AssemblyInfo.cs create mode 100644 rocks/Mono.Cecil.Rocks/Functional.cs create mode 100644 rocks/Mono.Cecil.Rocks/ILParser.cs create mode 100644 rocks/Mono.Cecil.Rocks/MethodBodyRocks.cs create mode 100644 rocks/Mono.Cecil.Rocks/MethodDefinitionRocks.cs create mode 100644 rocks/Mono.Cecil.Rocks/ModuleDefinitionRocks.cs create mode 100644 rocks/Mono.Cecil.Rocks/ParameterReferenceRocks.cs create mode 100644 rocks/Mono.Cecil.Rocks/SecurityDeclarationRocks.cs create mode 100644 rocks/Mono.Cecil.Rocks/TypeDefinitionRocks.cs create mode 100644 rocks/Mono.Cecil.Rocks/TypeReferenceRocks.cs create mode 100644 rocks/Test/.gitignore create mode 100644 rocks/Test/Mono.Cecil.Rocks.Tests.csproj create mode 100644 rocks/Test/Mono.Cecil.Tests/Addin.cs create mode 100644 rocks/Test/Mono.Cecil.Tests/MethodDefinitionRocksTests.cs create mode 100644 rocks/Test/Mono.Cecil.Tests/ModuleDefinitionRocksTests.cs create mode 100644 rocks/Test/Mono.Cecil.Tests/SecurityDeclarationRocksTests.cs create mode 100644 rocks/Test/Mono.Cecil.Tests/TypeDefinitionRocksTests.cs create mode 100644 rocks/Test/Mono.Cecil.Tests/TypeReferenceRocksTests.cs create mode 100644 rocks/Test/Resources/assemblies/decsec-att.dll create mode 100644 rocks/Test/Resources/assemblies/decsec-xml.dll create mode 100755 rocks/Test/Resources/cs/Types.cs create mode 100644 symbols/mdb/.gitignore create mode 100644 symbols/mdb/Mono.Cecil.Mdb.csproj create mode 100644 symbols/mdb/Mono.Cecil.Mdb/AssemblyInfo.cs create mode 100644 symbols/mdb/Mono.Cecil.Mdb/MdbReader.cs create mode 100644 symbols/mdb/Mono.Cecil.Mdb/MdbWriter.cs create mode 100644 symbols/mdb/Mono.CompilerServices.SymbolWriter/MonoSymbolFile.cs create mode 100644 symbols/mdb/Mono.CompilerServices.SymbolWriter/MonoSymbolTable.cs create mode 100644 symbols/mdb/Mono.CompilerServices.SymbolWriter/MonoSymbolWriter.cs create mode 100644 symbols/mdb/Mono.CompilerServices.SymbolWriter/SymbolWriterImpl.cs create mode 100644 symbols/mdb/Test/.gitignore create mode 100644 symbols/mdb/Test/Mono.Cecil.Mdb.Tests.csproj create mode 100644 symbols/mdb/Test/Mono.Cecil.Tests/Addin.cs create mode 100644 symbols/mdb/Test/Mono.Cecil.Tests/MdbTests.cs create mode 100644 symbols/mdb/Test/Resources/assemblies/hello.exe create mode 100644 symbols/mdb/Test/Resources/assemblies/hello.exe.mdb create mode 100644 symbols/pdb/.gitignore create mode 100644 symbols/pdb/Microsoft.Cci.Pdb/BitAccess.cs create mode 100644 symbols/pdb/Microsoft.Cci.Pdb/BitSet.cs create mode 100644 symbols/pdb/Microsoft.Cci.Pdb/CvInfo.cs create mode 100644 symbols/pdb/Microsoft.Cci.Pdb/DataStream.cs create mode 100644 symbols/pdb/Microsoft.Cci.Pdb/DbiDbgHdr.cs create mode 100644 symbols/pdb/Microsoft.Cci.Pdb/DbiHeader.cs create mode 100644 symbols/pdb/Microsoft.Cci.Pdb/DbiModuleInfo.cs create mode 100644 symbols/pdb/Microsoft.Cci.Pdb/DbiSecCon.cs create mode 100644 symbols/pdb/Microsoft.Cci.Pdb/IntHashTable.cs create mode 100644 symbols/pdb/Microsoft.Cci.Pdb/Interfaces.cs create mode 100755 symbols/pdb/Microsoft.Cci.Pdb/LICENSE create mode 100644 symbols/pdb/Microsoft.Cci.Pdb/MsfDirectory.cs create mode 100644 symbols/pdb/Microsoft.Cci.Pdb/PdbConstant.cs create mode 100644 symbols/pdb/Microsoft.Cci.Pdb/PdbDebugException.cs create mode 100644 symbols/pdb/Microsoft.Cci.Pdb/PdbException.cs create mode 100644 symbols/pdb/Microsoft.Cci.Pdb/PdbFile.cs create mode 100644 symbols/pdb/Microsoft.Cci.Pdb/PdbFileHeader.cs create mode 100644 symbols/pdb/Microsoft.Cci.Pdb/PdbFunction.cs create mode 100644 symbols/pdb/Microsoft.Cci.Pdb/PdbLine.cs create mode 100644 symbols/pdb/Microsoft.Cci.Pdb/PdbLines.cs create mode 100644 symbols/pdb/Microsoft.Cci.Pdb/PdbReader.cs create mode 100644 symbols/pdb/Microsoft.Cci.Pdb/PdbScope.cs create mode 100644 symbols/pdb/Microsoft.Cci.Pdb/PdbSlot.cs create mode 100644 symbols/pdb/Microsoft.Cci.Pdb/PdbSource.cs create mode 100644 symbols/pdb/Microsoft.Cci.Pdb/PdbWriter.cs create mode 100644 symbols/pdb/Microsoft.Cci.Pdb/SourceLocationProvider.cs create mode 100644 symbols/pdb/Mono.Cecil.Pdb.csproj create mode 100644 symbols/pdb/Mono.Cecil.Pdb/AssemblyInfo.cs create mode 100644 symbols/pdb/Mono.Cecil.Pdb/ISymUnmanagedDocumentWriter.cs create mode 100644 symbols/pdb/Mono.Cecil.Pdb/ISymUnmanagedWriter2.cs create mode 100644 symbols/pdb/Mono.Cecil.Pdb/ModuleMetadata.cs create mode 100644 symbols/pdb/Mono.Cecil.Pdb/PdbHelper.cs create mode 100644 symbols/pdb/Mono.Cecil.Pdb/PdbReader.cs create mode 100644 symbols/pdb/Mono.Cecil.Pdb/PdbWriter.cs create mode 100644 symbols/pdb/Mono.Cecil.Pdb/SymDocumentWriter.cs create mode 100644 symbols/pdb/Mono.Cecil.Pdb/SymWriter.cs create mode 100644 symbols/pdb/Test/.gitignore create mode 100644 symbols/pdb/Test/Mono.Cecil.Pdb.Tests.csproj create mode 100644 symbols/pdb/Test/Mono.Cecil.Tests/Addin.cs create mode 100644 symbols/pdb/Test/Mono.Cecil.Tests/Linq.cs create mode 100644 symbols/pdb/Test/Mono.Cecil.Tests/PdbTests.cs create mode 100644 symbols/pdb/Test/Resources/assemblies/test.exe create mode 100644 symbols/pdb/Test/Resources/assemblies/test.pdb diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..3629e370c --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +bin +obj +*.suo +*.user +*.pidb +*.userprefs +*.xml diff --git a/Mono.Cecil.Cil/Code.cs b/Mono.Cecil.Cil/Code.cs new file mode 100644 index 000000000..bd18b842a --- /dev/null +++ b/Mono.Cecil.Cil/Code.cs @@ -0,0 +1,252 @@ +// +// Code.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace Mono.Cecil.Cil { + + public enum Code { + Nop, + Break, + Ldarg_0, + Ldarg_1, + Ldarg_2, + Ldarg_3, + Ldloc_0, + Ldloc_1, + Ldloc_2, + Ldloc_3, + Stloc_0, + Stloc_1, + Stloc_2, + Stloc_3, + Ldarg_S, + Ldarga_S, + Starg_S, + Ldloc_S, + Ldloca_S, + Stloc_S, + Ldnull, + Ldc_I4_M1, + Ldc_I4_0, + Ldc_I4_1, + Ldc_I4_2, + Ldc_I4_3, + Ldc_I4_4, + Ldc_I4_5, + Ldc_I4_6, + Ldc_I4_7, + Ldc_I4_8, + Ldc_I4_S, + Ldc_I4, + Ldc_I8, + Ldc_R4, + Ldc_R8, + Dup, + Pop, + Jmp, + Call, + Calli, + Ret, + Br_S, + Brfalse_S, + Brtrue_S, + Beq_S, + Bge_S, + Bgt_S, + Ble_S, + Blt_S, + Bne_Un_S, + Bge_Un_S, + Bgt_Un_S, + Ble_Un_S, + Blt_Un_S, + Br, + Brfalse, + Brtrue, + Beq, + Bge, + Bgt, + Ble, + Blt, + Bne_Un, + Bge_Un, + Bgt_Un, + Ble_Un, + Blt_Un, + Switch, + Ldind_I1, + Ldind_U1, + Ldind_I2, + Ldind_U2, + Ldind_I4, + Ldind_U4, + Ldind_I8, + Ldind_I, + Ldind_R4, + Ldind_R8, + Ldind_Ref, + Stind_Ref, + Stind_I1, + Stind_I2, + Stind_I4, + Stind_I8, + Stind_R4, + Stind_R8, + Add, + Sub, + Mul, + Div, + Div_Un, + Rem, + Rem_Un, + And, + Or, + Xor, + Shl, + Shr, + Shr_Un, + Neg, + Not, + Conv_I1, + Conv_I2, + Conv_I4, + Conv_I8, + Conv_R4, + Conv_R8, + Conv_U4, + Conv_U8, + Callvirt, + Cpobj, + Ldobj, + Ldstr, + Newobj, + Castclass, + Isinst, + Conv_R_Un, + Unbox, + Throw, + Ldfld, + Ldflda, + Stfld, + Ldsfld, + Ldsflda, + Stsfld, + Stobj, + Conv_Ovf_I1_Un, + Conv_Ovf_I2_Un, + Conv_Ovf_I4_Un, + Conv_Ovf_I8_Un, + Conv_Ovf_U1_Un, + Conv_Ovf_U2_Un, + Conv_Ovf_U4_Un, + Conv_Ovf_U8_Un, + Conv_Ovf_I_Un, + Conv_Ovf_U_Un, + Box, + Newarr, + Ldlen, + Ldelema, + Ldelem_I1, + Ldelem_U1, + Ldelem_I2, + Ldelem_U2, + Ldelem_I4, + Ldelem_U4, + Ldelem_I8, + Ldelem_I, + Ldelem_R4, + Ldelem_R8, + Ldelem_Ref, + Stelem_I, + Stelem_I1, + Stelem_I2, + Stelem_I4, + Stelem_I8, + Stelem_R4, + Stelem_R8, + Stelem_Ref, + Ldelem_Any, + Stelem_Any, + Unbox_Any, + Conv_Ovf_I1, + Conv_Ovf_U1, + Conv_Ovf_I2, + Conv_Ovf_U2, + Conv_Ovf_I4, + Conv_Ovf_U4, + Conv_Ovf_I8, + Conv_Ovf_U8, + Refanyval, + Ckfinite, + Mkrefany, + Ldtoken, + Conv_U2, + Conv_U1, + Conv_I, + Conv_Ovf_I, + Conv_Ovf_U, + Add_Ovf, + Add_Ovf_Un, + Mul_Ovf, + Mul_Ovf_Un, + Sub_Ovf, + Sub_Ovf_Un, + Endfinally, + Leave, + Leave_S, + Stind_I, + Conv_U, + Arglist, + Ceq, + Cgt, + Cgt_Un, + Clt, + Clt_Un, + Ldftn, + Ldvirtftn, + Ldarg, + Ldarga, + Starg, + Ldloc, + Ldloca, + Stloc, + Localloc, + Endfilter, + Unaligned, + Volatile, + Tail, + Initobj, + Constrained, + Cpblk, + Initblk, + No, + Rethrow, + Sizeof, + Refanytype, + Readonly, + } +} diff --git a/Mono.Cecil.Cil/CodeReader.cs b/Mono.Cecil.Cil/CodeReader.cs new file mode 100644 index 000000000..4cfc7db75 --- /dev/null +++ b/Mono.Cecil.Cil/CodeReader.cs @@ -0,0 +1,604 @@ +// +// CodeReader.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +using Mono.Cecil.PE; +using Mono.Collections.Generic; + +using RVA = System.UInt32; + +namespace Mono.Cecil.Cil { + + sealed class CodeReader : ByteBuffer { + + readonly internal MetadataReader reader; + + int start; + Section code_section; + + MethodDefinition method; + MethodBody body; + + int Offset { + get { return base.position - start; } + } + + CodeReader (Section section, MetadataReader reader) + : base (section.Data) + { + this.code_section = section; + this.reader = reader; + } + + public static CodeReader CreateCodeReader (MetadataReader metadata) + { + return new CodeReader (metadata.image.MetadataSection, metadata); + } + + public MethodBody ReadMethodBody (MethodDefinition method) + { + this.method = method; + this.body = new MethodBody (method); + + reader.context = method; + + ReadMethodBody (); + + return this.body; + } + + public void MoveTo (int rva) + { + if (!IsInSection (rva)) { + code_section = reader.image.GetSectionAtVirtualAddress ((uint) rva); + Reset (code_section.Data); + } + + base.position = rva - (int) code_section.VirtualAddress; + } + + bool IsInSection (int rva) + { + return code_section.VirtualAddress <= rva && rva < code_section.VirtualAddress + code_section.SizeOfRawData; + } + + void ReadMethodBody () + { + MoveTo (method.RVA); + + var flags = ReadByte (); + switch (flags & 0x3) { + case 0x2: // tiny + body.code_size = flags >> 2; + body.MaxStackSize = 8; + ReadCode (); + break; + case 0x3: // fat + base.position--; + ReadFatMethod (); + break; + default: + throw new InvalidOperationException (); + } + + var symbol_reader = reader.module.SymbolReader; + + if (symbol_reader != null) { + var instructions = body.Instructions; + symbol_reader.Read (body, offset => GetInstruction (instructions, offset)); + } + } + + void ReadFatMethod () + { + var flags = ReadUInt16 (); + body.max_stack_size = ReadUInt16 (); + body.code_size = (int) ReadUInt32 (); + body.local_var_token = new MetadataToken (ReadUInt32 ()); + body.init_locals = (flags & 0x10) != 0; + + if (body.local_var_token.RID != 0) + body.variables = ReadVariables (body.local_var_token); + + ReadCode (); + + if ((flags & 0x8) != 0) + ReadSection (); + } + + public VariableDefinitionCollection ReadVariables (MetadataToken local_var_token) + { + var position = reader.position; + var variables = reader.ReadVariables (local_var_token); + reader.position = position; + + return variables; + } + + void ReadCode () + { + start = position; + var code_size = body.code_size; + + if (code_size < 0 || buffer.Length <= (uint) (code_size + position)) + code_size = 0; + + var end = start + code_size; + var instructions = body.instructions = new InstructionCollection (code_size / 3); + + while (position < end) { + var offset = base.position - start; + var opcode = ReadOpCode (); + var current = new Instruction (offset, opcode); + + if (opcode.OperandType != OperandType.InlineNone) + current.operand = ReadOperand (current); + + instructions.Add (current); + } + + ResolveBranches (instructions); + } + + OpCode ReadOpCode () + { + var il_opcode = ReadByte (); + return il_opcode != 0xfe + ? OpCodes.OneByteOpCode [il_opcode] + : OpCodes.TwoBytesOpCode [ReadByte ()]; + } + + object ReadOperand (Instruction instruction) + { + switch (instruction.opcode.OperandType) { + case OperandType.InlineSwitch: + var length = ReadInt32 (); + var base_offset = Offset + (4 * length); + var branches = new int [length]; + for (int i = 0; i < length; i++) + branches [i] = base_offset + ReadInt32 (); + return branches; + case OperandType.ShortInlineBrTarget: + return ReadSByte () + Offset; + case OperandType.InlineBrTarget: + return ReadInt32 () + Offset; + case OperandType.ShortInlineI: + if (instruction.opcode == OpCodes.Ldc_I4_S) + return ReadSByte (); + + return ReadByte (); + case OperandType.InlineI: + return ReadInt32 (); + case OperandType.ShortInlineR: + return ReadSingle (); + case OperandType.InlineR: + return ReadDouble (); + case OperandType.InlineI8: + return ReadInt64 (); + case OperandType.ShortInlineVar: + return GetVariable (ReadByte ()); + case OperandType.InlineVar: + return GetVariable (ReadUInt16 ()); + case OperandType.ShortInlineArg: + return GetParameter (ReadByte ()); + case OperandType.InlineArg: + return GetParameter (ReadUInt16 ()); + case OperandType.InlineSig: + return GetCallSite (ReadToken ()); + case OperandType.InlineString: + return GetString (ReadToken ()); + case OperandType.InlineTok: + case OperandType.InlineType: + case OperandType.InlineMethod: + case OperandType.InlineField: + return reader.LookupToken (ReadToken ()); + default: + throw new NotSupportedException (); + } + } + + public string GetString (MetadataToken token) + { + return reader.image.UserStringHeap.Read (token.RID); + } + + public ParameterDefinition GetParameter (int index) + { + return body.GetParameter (index); + } + + public VariableDefinition GetVariable (int index) + { + return body.GetVariable (index); + } + + public CallSite GetCallSite (MetadataToken token) + { + return reader.ReadCallSite (token); + } + + void ResolveBranches (Collection instructions) + { + var items = instructions.items; + var size = instructions.size; + + for (int i = 0; i < size; i++) { + var instruction = items [i]; + switch (instruction.opcode.OperandType) { + case OperandType.ShortInlineBrTarget: + case OperandType.InlineBrTarget: + instruction.operand = GetInstruction ((int) instruction.operand); + break; + case OperandType.InlineSwitch: + var offsets = (int []) instruction.operand; + var branches = new Instruction [offsets.Length]; + for (int j = 0; j < offsets.Length; j++) + branches [j] = GetInstruction (offsets [j]); + + instruction.operand = branches; + break; + } + } + } + + Instruction GetInstruction (int offset) + { + return GetInstruction (body.Instructions, offset); + } + + static Instruction GetInstruction (Collection instructions, int offset) + { + var size = instructions.size; + var items = instructions.items; + if (offset < 0 || offset > items [size - 1].offset) + return null; + + int min = 0; + int max = size - 1; + while (min <= max) { + int mid = min + ((max - min) / 2); + var instruction = items [mid]; + var instruction_offset = instruction.offset; + + if (offset == instruction_offset) + return instruction; + + if (offset < instruction_offset) + max = mid - 1; + else + min = mid + 1; + } + + return null; + } + + void ReadSection () + { + Align (4); + + const byte fat_format = 0x40; + const byte more_sects = 0x80; + + var flags = ReadByte (); + if ((flags & fat_format) == 0) + ReadSmallSection (); + else + ReadFatSection (); + + if ((flags & more_sects) != 0) + ReadSection (); + } + + void ReadSmallSection () + { + var count = ReadByte () / 12; + Advance (2); + + ReadExceptionHandlers ( + count, + () => (int) ReadUInt16 (), + () => (int) ReadByte ()); + } + + void ReadFatSection () + { + position--; + var count = (ReadInt32 () >> 8) / 24; + + ReadExceptionHandlers ( + count, + ReadInt32, + ReadInt32); + } + + // inline ? + void ReadExceptionHandlers (int count, Func read_entry, Func read_length) + { + for (int i = 0; i < count; i++) { + var handler = new ExceptionHandler ( + (ExceptionHandlerType) (read_entry () & 0x7)); + + handler.TryStart = GetInstruction (read_entry ()); + handler.TryEnd = GetInstruction (handler.TryStart.Offset + read_length ()); + + handler.HandlerStart = GetInstruction (read_entry ()); + handler.HandlerEnd = GetInstruction (handler.HandlerStart.Offset + read_length ()); + + ReadExceptionHandlerSpecific (handler); + + this.body.ExceptionHandlers.Add (handler); + } + } + + void ReadExceptionHandlerSpecific (ExceptionHandler handler) + { + switch (handler.HandlerType) { + case ExceptionHandlerType.Catch: + handler.CatchType = (TypeReference) reader.LookupToken (ReadToken ()); + break; + case ExceptionHandlerType.Filter: + handler.FilterStart = GetInstruction (ReadInt32 ()); + handler.FilterEnd = handler.HandlerStart.Previous; + break; + default: + Advance (4); + break; + } + } + + void Align (int align) + { + align--; + Advance (((position + align) & ~align) - position); + } + + public MetadataToken ReadToken () + { + return new MetadataToken (ReadUInt32 ()); + } + +#if !READ_ONLY + + public ByteBuffer PatchRawMethodBody (MethodDefinition method, CodeWriter writer, out MethodSymbols symbols) + { + var buffer = new ByteBuffer (); + symbols = new MethodSymbols (method.Name); + + this.method = method; + reader.context = method; + + MoveTo (method.RVA); + + var flags = ReadByte (); + + MetadataToken local_var_token; + + switch (flags & 0x3) { + case 0x2: // tiny + buffer.WriteByte (flags); + local_var_token = MetadataToken.Zero; + symbols.code_size = flags >> 2; + PatchRawCode (buffer, symbols.code_size, writer); + break; + case 0x3: // fat + base.position--; + + PatchRawFatMethod (buffer, symbols, writer, out local_var_token); + break; + default: + throw new NotSupportedException (); + } + + var symbol_reader = reader.module.SymbolReader; + if (symbol_reader != null && writer.metadata.write_symbols) { + symbols.method_token = GetOriginalToken (writer.metadata, method); + symbols.local_var_token = local_var_token; + symbol_reader.Read (symbols); + } + + return buffer; + } + + void PatchRawFatMethod (ByteBuffer buffer, MethodSymbols symbols, CodeWriter writer, out MetadataToken local_var_token) + { + var flags = ReadUInt16 (); + buffer.WriteUInt16 (flags); + buffer.WriteUInt16 (ReadUInt16 ()); + symbols.code_size = ReadInt32 (); + buffer.WriteInt32 (symbols.code_size); + local_var_token = ReadToken (); + + if (local_var_token.RID > 0) { + var variables = symbols.variables = ReadVariables (local_var_token); + buffer.WriteUInt32 (variables != null + ? writer.GetStandAloneSignature (symbols.variables).ToUInt32 () + : 0); + } else + buffer.WriteUInt32 (0); + + PatchRawCode (buffer, symbols.code_size, writer); + + if ((flags & 0x8) != 0) + PatchRawSection (buffer, writer.metadata); + } + + static MetadataToken GetOriginalToken (MetadataBuilder metadata, MethodDefinition method) + { + MetadataToken original; + if (metadata.TryGetOriginalMethodToken (method.token, out original)) + return original; + + return MetadataToken.Zero; + } + + void PatchRawCode (ByteBuffer buffer, int code_size, CodeWriter writer) + { + var metadata = writer.metadata; + buffer.WriteBytes (ReadBytes (code_size)); + var end = buffer.position; + buffer.position -= code_size; + + while (buffer.position < end) { + OpCode opcode; + var il_opcode = buffer.ReadByte (); + if (il_opcode != 0xfe) { + opcode = OpCodes.OneByteOpCode [il_opcode]; + } else { + var il_opcode2 = buffer.ReadByte (); + opcode = OpCodes.TwoBytesOpCode [il_opcode2]; + } + + switch (opcode.OperandType) { + case OperandType.ShortInlineI: + case OperandType.ShortInlineBrTarget: + case OperandType.ShortInlineVar: + case OperandType.ShortInlineArg: + buffer.position += 1; + break; + case OperandType.InlineVar: + case OperandType.InlineArg: + buffer.position += 2; + break; + case OperandType.InlineBrTarget: + case OperandType.ShortInlineR: + case OperandType.InlineI: + buffer.position += 4; + break; + case OperandType.InlineI8: + case OperandType.InlineR: + buffer.position += 8; + break; + case OperandType.InlineSwitch: + var length = buffer.ReadInt32 (); + buffer.position += length * 4; + break; + case OperandType.InlineString: + var @string = GetString (new MetadataToken (buffer.ReadUInt32 ())); + buffer.position -= 4; + buffer.WriteUInt32 ( + new MetadataToken ( + TokenType.String, + metadata.user_string_heap.GetStringIndex (@string)).ToUInt32 ()); + break; + case OperandType.InlineSig: + var call_site = GetCallSite (new MetadataToken (buffer.ReadUInt32 ())); + buffer.position -= 4; + buffer.WriteUInt32 (writer.GetStandAloneSignature (call_site).ToUInt32 ()); + break; + case OperandType.InlineTok: + case OperandType.InlineType: + case OperandType.InlineMethod: + case OperandType.InlineField: + var provider = reader.LookupToken (new MetadataToken (buffer.ReadUInt32 ())); + buffer.position -= 4; + buffer.WriteUInt32 (metadata.LookupToken (provider).ToUInt32 ()); + break; + } + } + } + + void PatchRawSection (ByteBuffer buffer, MetadataBuilder metadata) + { + var position = base.position; + Align (4); + buffer.WriteBytes (base.position - position); + + const byte fat_format = 0x40; + const byte more_sects = 0x80; + + var flags = ReadByte (); + if ((flags & fat_format) == 0) { + buffer.WriteByte (flags); + PatchRawSmallSection (buffer, metadata); + } else + PatchRawFatSection (buffer, metadata); + + if ((flags & more_sects) != 0) + PatchRawSection (buffer, metadata); + } + + void PatchRawSmallSection (ByteBuffer buffer, MetadataBuilder metadata) + { + var length = ReadByte (); + buffer.WriteByte (length); + Advance (2); + + buffer.WriteUInt16 (0); + + var count = length / 12; + + PatchRawExceptionHandlers (buffer, metadata, count, false); + } + + void PatchRawFatSection (ByteBuffer buffer, MetadataBuilder metadata) + { + position--; + var length = ReadInt32 (); + buffer.WriteInt32 (length); + + var count = (length >> 8) / 24; + + PatchRawExceptionHandlers (buffer, metadata, count, true); + } + + void PatchRawExceptionHandlers (ByteBuffer buffer, MetadataBuilder metadata, int count, bool fat_entry) + { + const int fat_entry_size = 16; + const int small_entry_size = 6; + + for (int i = 0; i < count; i++) { + ExceptionHandlerType handler_type; + if (fat_entry) { + var type = ReadUInt32 (); + handler_type = (ExceptionHandlerType) (type & 0x7); + buffer.WriteUInt32 (type); + } else { + var type = ReadUInt16 (); + handler_type = (ExceptionHandlerType) (type & 0x7); + buffer.WriteUInt16 (type); + } + + buffer.WriteBytes (ReadBytes (fat_entry ? fat_entry_size : small_entry_size)); + + switch (handler_type) { + case ExceptionHandlerType.Catch: + var exception = reader.LookupToken (ReadToken ()); + buffer.WriteUInt32 (metadata.LookupToken (exception).ToUInt32 ()); + break; + default: + buffer.WriteUInt32 (ReadUInt32 ()); + break; + } + } + } + +#endif + + } +} diff --git a/Mono.Cecil.Cil/CodeWriter.cs b/Mono.Cecil.Cil/CodeWriter.cs new file mode 100644 index 000000000..8bf072241 --- /dev/null +++ b/Mono.Cecil.Cil/CodeWriter.cs @@ -0,0 +1,638 @@ +// +// CodeWriter.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Generic; + +using Mono.Collections.Generic; + +using Mono.Cecil.Metadata; +using Mono.Cecil.PE; + +using RVA = System.UInt32; + +#if !READ_ONLY + +namespace Mono.Cecil.Cil { + + sealed class CodeWriter : ByteBuffer { + + readonly RVA code_base; + internal readonly MetadataBuilder metadata; + readonly Dictionary standalone_signatures; + + RVA current; + MethodBody body; + + public CodeWriter (MetadataBuilder metadata) + : base (0) + { + this.code_base = metadata.text_map.GetNextRVA (TextSegment.CLIHeader); + this.current = code_base; + this.metadata = metadata; + this.standalone_signatures = new Dictionary (); + } + + public RVA WriteMethodBody (MethodDefinition method) + { + var rva = BeginMethod (); + + if (IsUnresolved (method)) { + if (method.rva == 0) + return 0; + + WriteUnresolvedMethodBody (method); + } else { + if (IsEmptyMethodBody (method.Body)) + return 0; + + WriteResolvedMethodBody (method); + } + + Align (4); + + EndMethod (); + return rva; + } + + static bool IsEmptyMethodBody (MethodBody body) + { + return body.instructions.IsNullOrEmpty () + && body.variables.IsNullOrEmpty (); + } + + static bool IsUnresolved (MethodDefinition method) + { + return method.HasBody && method.HasImage && method.body == null; + } + + void WriteUnresolvedMethodBody (MethodDefinition method) + { + var code_reader = metadata.module.Read (method, (_, reader) => reader.code); + + MethodSymbols symbols; + var buffer = code_reader.PatchRawMethodBody (method, this, out symbols); + + WriteBytes (buffer); + + if (symbols.instructions.IsNullOrEmpty ()) + return; + + symbols.method_token = method.token; + symbols.local_var_token = GetLocalVarToken (buffer, symbols); + + var symbol_writer = metadata.symbol_writer; + if (symbol_writer != null) + symbol_writer.Write (symbols); + } + + static MetadataToken GetLocalVarToken (ByteBuffer buffer, MethodSymbols symbols) + { + if (symbols.variables.IsNullOrEmpty ()) + return MetadataToken.Zero; + + buffer.position = 8; + return new MetadataToken (buffer.ReadUInt32 ()); + } + + void WriteResolvedMethodBody (MethodDefinition method) + { + body = method.Body; + ComputeHeader (); + if (RequiresFatHeader ()) + WriteFatHeader (); + else + WriteByte ((byte) (0x2 | (body.CodeSize << 2))); // tiny + + WriteInstructions (); + + if (body.HasExceptionHandlers) + WriteExceptionHandlers (); + + var symbol_writer = metadata.symbol_writer; + if (symbol_writer != null) + symbol_writer.Write (body); + } + + void WriteFatHeader () + { + var body = this.body; + byte flags = 0x3; // fat + if (body.InitLocals) + flags |= 0x10; // init locals + if (body.HasExceptionHandlers) + flags |= 0x8; // more sections + + WriteByte (flags); + WriteByte (0x30); + WriteInt16 ((short) body.max_stack_size); + WriteInt32 (body.code_size); + body.local_var_token = body.HasVariables + ? GetStandAloneSignature (body.Variables) + : MetadataToken.Zero; + WriteMetadataToken (body.local_var_token); + } + + void WriteInstructions () + { + var instructions = body.Instructions; + var items = instructions.items; + var size = instructions.size; + + for (int i = 0; i < size; i++) { + var instruction = items [i]; + WriteOpCode (instruction.opcode); + WriteOperand (instruction); + } + } + + void WriteOpCode (OpCode opcode) + { + if (opcode.Size == 1) { + WriteByte (opcode.Op2); + } else { + WriteByte (opcode.Op1); + WriteByte (opcode.Op2); + } + } + + void WriteOperand (Instruction instruction) + { + var opcode = instruction.opcode; + var operand_type = opcode.OperandType; + if (operand_type == OperandType.InlineNone) + return; + + var operand = instruction.operand; + if (operand == null) + throw new ArgumentException (); + + switch (operand_type) { + case OperandType.InlineSwitch: { + var targets = (Instruction []) operand; + WriteInt32 (targets.Length); + var diff = instruction.Offset + opcode.Size + (4 * (targets.Length + 1)); + for (int i = 0; i < targets.Length; i++) + WriteInt32 (GetTargetOffset (targets [i]) - diff); + break; + } + case OperandType.ShortInlineBrTarget: { + var target = (Instruction) operand; + WriteSByte ((sbyte) (GetTargetOffset (target) - (instruction.Offset + opcode.Size + 1))); + break; + } + case OperandType.InlineBrTarget: { + var target = (Instruction) operand; + WriteInt32 (GetTargetOffset (target) - (instruction.Offset + opcode.Size + 4)); + break; + } + case OperandType.ShortInlineVar: + WriteByte ((byte) GetVariableIndex ((VariableDefinition) operand)); + break; + case OperandType.ShortInlineArg: + WriteByte ((byte) GetParameterIndex ((ParameterDefinition) operand)); + break; + case OperandType.InlineVar: + WriteInt16 ((short) GetVariableIndex ((VariableDefinition) operand)); + break; + case OperandType.InlineArg: + WriteInt16 ((short) GetParameterIndex ((ParameterDefinition) operand)); + break; + case OperandType.InlineSig: + WriteMetadataToken (GetStandAloneSignature ((CallSite) operand)); + break; + case OperandType.ShortInlineI: + if (opcode == OpCodes.Ldc_I4_S) + WriteSByte ((sbyte) operand); + else + WriteByte ((byte) operand); + break; + case OperandType.InlineI: + WriteInt32 ((int) operand); + break; + case OperandType.InlineI8: + WriteInt64 ((long) operand); + break; + case OperandType.ShortInlineR: + WriteSingle ((float) operand); + break; + case OperandType.InlineR: + WriteDouble ((double) operand); + break; + case OperandType.InlineString: + WriteMetadataToken ( + new MetadataToken ( + TokenType.String, + GetUserStringIndex ((string) operand))); + break; + case OperandType.InlineType: + case OperandType.InlineField: + case OperandType.InlineMethod: + case OperandType.InlineTok: + WriteMetadataToken (metadata.LookupToken ((IMetadataTokenProvider) operand)); + break; + default: + throw new ArgumentException (); + } + } + + int GetTargetOffset (Instruction instruction) + { + if (instruction == null) { + var last = body.instructions [body.instructions.size - 1]; + return last.offset + last.GetSize (); + } + + return instruction.offset; + } + + uint GetUserStringIndex (string @string) + { + if (@string == null) + return 0; + + return metadata.user_string_heap.GetStringIndex (@string); + } + + static int GetVariableIndex (VariableDefinition variable) + { + return variable.Index; + } + + int GetParameterIndex (ParameterDefinition parameter) + { + if (body.method.HasThis) { + if (parameter == body.this_parameter) + return 0; + + return parameter.Index + 1; + } + + return parameter.Index; + } + + bool RequiresFatHeader () + { + var body = this.body; + return body.CodeSize >= 64 + || body.InitLocals + || body.HasVariables + || body.HasExceptionHandlers + || body.MaxStackSize > 8; + } + + void ComputeHeader () + { + int offset = 0; + var instructions = body.instructions; + var items = instructions.items; + var count = instructions.size; + var stack_size = 0; + var max_stack = 0; + Dictionary stack_sizes = null; + + if (body.HasExceptionHandlers) + ComputeExceptionHandlerStackSize (ref stack_sizes); + + for (int i = 0; i < count; i++) { + var instruction = items [i]; + instruction.offset = offset; + offset += instruction.GetSize (); + + ComputeStackSize (instruction, ref stack_sizes, ref stack_size, ref max_stack); + } + + body.code_size = offset; + body.max_stack_size = max_stack; + } + + void ComputeExceptionHandlerStackSize (ref Dictionary stack_sizes) + { + var exception_handlers = body.ExceptionHandlers; + + for (int i = 0; i < exception_handlers.Count; i++) { + var exception_handler = exception_handlers [i]; + + switch (exception_handler.HandlerType) { + case ExceptionHandlerType.Catch: + AddExceptionStackSize (exception_handler.HandlerStart, ref stack_sizes); + break; + case ExceptionHandlerType.Filter: + AddExceptionStackSize (exception_handler.FilterStart, ref stack_sizes); + AddExceptionStackSize (exception_handler.HandlerStart, ref stack_sizes); + break; + } + } + } + + static void AddExceptionStackSize (Instruction handler_start, ref Dictionary stack_sizes) + { + if (handler_start == null) + return; + + if (stack_sizes == null) + stack_sizes = new Dictionary (); + + stack_sizes [handler_start] = 1; + } + + static void ComputeStackSize (Instruction instruction, ref Dictionary stack_sizes, ref int stack_size, ref int max_stack) + { + int computed_size; + if (stack_sizes != null && stack_sizes.TryGetValue (instruction, out computed_size)) + stack_size = computed_size; + + max_stack = System.Math.Max (max_stack, stack_size); + ComputeStackDelta (instruction, ref stack_size); + max_stack = System.Math.Max (max_stack, stack_size); + + CopyBranchStackSize (instruction, ref stack_sizes, stack_size); + ComputeStackSize (instruction, ref stack_size); + } + + static void CopyBranchStackSize (Instruction instruction, ref Dictionary stack_sizes, int stack_size) + { + if (stack_size == 0) + return; + + switch (instruction.opcode.OperandType) { + case OperandType.ShortInlineBrTarget: + case OperandType.InlineBrTarget: + CopyBranchStackSize (ref stack_sizes, (Instruction) instruction.operand, stack_size); + break; + case OperandType.InlineSwitch: + var targets = (Instruction[]) instruction.operand; + for (int i = 0; i < targets.Length; i++) + CopyBranchStackSize (ref stack_sizes, targets [i], stack_size); + break; + } + } + + static void CopyBranchStackSize (ref Dictionary stack_sizes, Instruction target, int stack_size) + { + if (stack_sizes == null) + stack_sizes = new Dictionary (); + + int branch_stack_size = stack_size; + + int computed_size; + if (stack_sizes.TryGetValue (target, out computed_size)) + branch_stack_size = System.Math.Max (branch_stack_size, computed_size); + + stack_sizes [target] = branch_stack_size; + } + + static void ComputeStackSize (Instruction instruction, ref int stack_size) + { + switch (instruction.opcode.FlowControl) { + case FlowControl.Branch: + case FlowControl.Break: + case FlowControl.Throw: + case FlowControl.Return: + stack_size = 0; + break; + } + } + + static void ComputeStackDelta (Instruction instruction, ref int stack_size) + { + switch (instruction.opcode.FlowControl) { + case FlowControl.Call: { + var method = (IMethodSignature) instruction.operand; + stack_size -= (method.HasParameters ? method.Parameters.Count : 0) + + (method.HasThis && instruction.opcode.Code != Code.Newobj ? 1 : 0); + stack_size += (method.ReturnType.etype == ElementType.Void ? 0 : 1) + + (method.HasThis && instruction.opcode.Code == Code.Newobj ? 1 : 0); + break; + } + default: + ComputePopDelta (instruction.opcode.StackBehaviourPop, ref stack_size); + ComputePushDelta (instruction.opcode.StackBehaviourPush, ref stack_size); + break; + } + } + + static void ComputePopDelta (StackBehaviour pop_behavior, ref int stack_size) + { + switch (pop_behavior) { + case StackBehaviour.Popi: + case StackBehaviour.Popref: + case StackBehaviour.Pop1: + stack_size--; + break; + case StackBehaviour.Pop1_pop1: + case StackBehaviour.Popi_pop1: + case StackBehaviour.Popi_popi: + case StackBehaviour.Popi_popi8: + case StackBehaviour.Popi_popr4: + case StackBehaviour.Popi_popr8: + case StackBehaviour.Popref_pop1: + case StackBehaviour.Popref_popi: + stack_size -= 2; + break; + case StackBehaviour.Popi_popi_popi: + case StackBehaviour.Popref_popi_popi: + case StackBehaviour.Popref_popi_popi8: + case StackBehaviour.Popref_popi_popr4: + case StackBehaviour.Popref_popi_popr8: + case StackBehaviour.Popref_popi_popref: + stack_size -= 3; + break; + case StackBehaviour.PopAll: + stack_size = 0; + break; + } + } + + static void ComputePushDelta (StackBehaviour push_behaviour, ref int stack_size) + { + switch (push_behaviour) { + case StackBehaviour.Push1: + case StackBehaviour.Pushi: + case StackBehaviour.Pushi8: + case StackBehaviour.Pushr4: + case StackBehaviour.Pushr8: + case StackBehaviour.Pushref: + stack_size++; + break; + case StackBehaviour.Push1_push1: + stack_size += 2; + break; + } + } + + void WriteExceptionHandlers () + { + Align (4); + + var handlers = body.ExceptionHandlers; + + if (handlers.Count < 0x15 && !RequiresFatSection (handlers)) + WriteSmallSection (handlers); + else + WriteFatSection (handlers); + } + + static bool RequiresFatSection (Collection handlers) + { + for (int i = 0; i < handlers.Count; i++) { + var handler = handlers [i]; + + if (IsFatRange (handler.TryStart, handler.TryEnd)) + return true; + + if (IsFatRange (handler.HandlerStart, handler.HandlerEnd)) + return true; + + if (handler.HandlerType == ExceptionHandlerType.Filter + && IsFatRange (handler.FilterStart, handler.FilterEnd)) + return true; + } + + return false; + } + + static bool IsFatRange (Instruction start, Instruction end) + { + if (end == null) + return true; + + return end.Offset - start.Offset > 255 || start.Offset > 65535; + } + + void WriteSmallSection (Collection handlers) + { + const byte eh_table = 0x1; + + WriteByte (eh_table); + WriteByte ((byte) (handlers.Count * 12 + 4)); + WriteBytes (2); + + WriteExceptionHandlers ( + handlers, + i => WriteUInt16 ((ushort) i), + i => WriteByte ((byte) i)); + } + + void WriteFatSection (Collection handlers) + { + const byte eh_table = 0x1; + const byte fat_format = 0x40; + + WriteByte (eh_table | fat_format); + + int size = handlers.Count * 24 + 4; + WriteByte ((byte) (size & 0xff)); + WriteByte ((byte) ((size >> 8) & 0xff)); + WriteByte ((byte) ((size >> 16) & 0xff)); + + WriteExceptionHandlers (handlers, WriteInt32, WriteInt32); + } + + void WriteExceptionHandlers (Collection handlers, Action write_entry, Action write_length) + { + for (int i = 0; i < handlers.Count; i++) { + var handler = handlers [i]; + + write_entry ((int) handler.HandlerType); + + write_entry (handler.TryStart.Offset); + write_length (GetTargetOffset (handler.TryEnd) - handler.TryStart.Offset); + + write_entry (handler.HandlerStart.Offset); + write_length (GetTargetOffset (handler.HandlerEnd) - handler.HandlerStart.Offset); + + WriteExceptionHandlerSpecific (handler); + } + } + + void WriteExceptionHandlerSpecific (ExceptionHandler handler) + { + switch (handler.HandlerType) { + case ExceptionHandlerType.Catch: + WriteMetadataToken (metadata.LookupToken (handler.CatchType)); + break; + case ExceptionHandlerType.Filter: + WriteInt32 (handler.FilterStart.Offset); + break; + default: + WriteInt32 (0); + break; + } + } + + public MetadataToken GetStandAloneSignature (Collection variables) + { + var signature = metadata.GetLocalVariableBlobIndex (variables); + + return GetStandAloneSignatureToken (signature); + } + + public MetadataToken GetStandAloneSignature (CallSite call_site) + { + var signature = metadata.GetCallSiteBlobIndex (call_site); + var token = GetStandAloneSignatureToken (signature); + call_site.MetadataToken = token; + return token; + } + + MetadataToken GetStandAloneSignatureToken (uint signature) + { + MetadataToken token; + if (standalone_signatures.TryGetValue (signature, out token)) + return token; + + token = new MetadataToken (TokenType.Signature, metadata.AddStandAloneSignature (signature)); + standalone_signatures.Add (signature, token); + return token; + } + + RVA BeginMethod () + { + return current; + } + + void WriteMetadataToken (MetadataToken token) + { + WriteUInt32 (token.ToUInt32 ()); + } + + void Align (int align) + { + align--; + WriteBytes (((position + align) & ~align) - position); + } + + void EndMethod () + { + current = (RVA) (code_base + position); + } + } +} + +#endif diff --git a/Mono.Cecil.Cil/Document.cs b/Mono.Cecil.Cil/Document.cs new file mode 100644 index 000000000..e46d2c1d8 --- /dev/null +++ b/Mono.Cecil.Cil/Document.cs @@ -0,0 +1,111 @@ +// +// Document.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace Mono.Cecil.Cil { + + public enum DocumentType { + Other, + Text, + } + + public enum DocumentHashAlgorithm { + None, + MD5, + SHA1, + } + + public enum DocumentLanguage { + Other, + C, + Cpp, + CSharp, + Basic, + Java, + Cobol, + Pascal, + Cil, + JScript, + Smc, + MCpp, + } + + public enum DocumentLanguageVendor { + Other, + Microsoft, + } + + public sealed class Document { + + string url; + + byte type; + byte hash_algorithm; + byte language; + byte language_vendor; + + byte [] hash; + + public string Url { + get { return url; } + set { url = value; } + } + + public DocumentType Type { + get { return (DocumentType) type; } + set { type = (byte) value; } + } + + public DocumentHashAlgorithm HashAlgorithm { + get { return (DocumentHashAlgorithm) hash_algorithm; } + set { hash_algorithm = (byte) value; } + } + + public DocumentLanguage Language { + get { return (DocumentLanguage) language; } + set { language = (byte) value; } + } + + public DocumentLanguageVendor LanguageVendor { + get { return (DocumentLanguageVendor) language_vendor; } + set { language_vendor = (byte) value; } + } + + public byte [] Hash { + get { return hash; } + set { hash = value; } + } + + public Document (string url) + { + this.url = url; + this.hash = Empty.Array; + } + } +} diff --git a/Mono.Cecil.Cil/ExceptionHandler.cs b/Mono.Cecil.Cil/ExceptionHandler.cs new file mode 100644 index 000000000..a76f8f397 --- /dev/null +++ b/Mono.Cecil.Cil/ExceptionHandler.cs @@ -0,0 +1,95 @@ +// +// ExceptionHandler.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace Mono.Cecil.Cil { + + public enum ExceptionHandlerType { + Catch = 0, + Filter = 1, + Finally = 2, + Fault = 4, + } + + public sealed class ExceptionHandler { + + Instruction try_start; + Instruction try_end; + Instruction filter_start; + Instruction filter_end; + Instruction handler_start; + Instruction handler_end; + + TypeReference catch_type; + ExceptionHandlerType handler_type; + + public Instruction TryStart { + get { return try_start; } + set { try_start = value; } + } + + public Instruction TryEnd { + get { return try_end; } + set { try_end = value; } + } + + public Instruction FilterStart { + get { return filter_start; } + set { filter_start = value; } + } + + public Instruction FilterEnd { + get { return filter_end; } + set { filter_end = value; } + } + + public Instruction HandlerStart { + get { return handler_start; } + set { handler_start = value; } + } + + public Instruction HandlerEnd { + get { return handler_end; } + set { handler_end = value; } + } + + public TypeReference CatchType { + get { return catch_type; } + set { catch_type = value; } + } + + public ExceptionHandlerType HandlerType { + get { return handler_type; } + set { handler_type = value; } + } + + public ExceptionHandler (ExceptionHandlerType handlerType) + { + this.handler_type = handlerType; + } + } +} diff --git a/Mono.Cecil.Cil/ILProcessor.cs b/Mono.Cecil.Cil/ILProcessor.cs new file mode 100644 index 000000000..1300b3e6b --- /dev/null +++ b/Mono.Cecil.Cil/ILProcessor.cs @@ -0,0 +1,278 @@ +// +// ILProcessor.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +using Mono.Collections.Generic; + +namespace Mono.Cecil.Cil { + + public sealed class ILProcessor { + + readonly MethodBody body; + readonly Collection instructions; + + public MethodBody Body { + get { return body; } + } + + internal ILProcessor (MethodBody body) + { + this.body = body; + this.instructions = body.Instructions; + } + + public Instruction Create (OpCode opcode) + { + return Instruction.Create (opcode); + } + + public Instruction Create (OpCode opcode, TypeReference type) + { + return Instruction.Create (opcode, type); + } + + public Instruction Create (OpCode opcode, CallSite site) + { + return Instruction.Create (opcode, site); + } + + public Instruction Create (OpCode opcode, MethodReference method) + { + return Instruction.Create (opcode, method); + } + + public Instruction Create (OpCode opcode, FieldReference field) + { + return Instruction.Create (opcode, field); + } + + public Instruction Create (OpCode opcode, string value) + { + return Instruction.Create (opcode, value); + } + + public Instruction Create (OpCode opcode, sbyte value) + { + return Instruction.Create (opcode, value); + } + + public Instruction Create (OpCode opcode, byte value) + { + if (opcode.OperandType == OperandType.ShortInlineVar) + return Instruction.Create (opcode, body.Variables [value]); + + if (opcode.OperandType == OperandType.ShortInlineArg) + return Instruction.Create (opcode, body.GetParameter (value)); + + return Instruction.Create (opcode, value); + } + + public Instruction Create (OpCode opcode, int value) + { + if (opcode.OperandType == OperandType.InlineVar) + return Instruction.Create (opcode, body.Variables [value]); + + if (opcode.OperandType == OperandType.InlineArg) + return Instruction.Create (opcode, body.GetParameter (value)); + + return Instruction.Create (opcode, value); + } + + public Instruction Create (OpCode opcode, long value) + { + return Instruction.Create (opcode, value); + } + + public Instruction Create (OpCode opcode, float value) + { + return Instruction.Create (opcode, value); + } + + public Instruction Create (OpCode opcode, double value) + { + return Instruction.Create (opcode, value); + } + + public Instruction Create (OpCode opcode, Instruction target) + { + return Instruction.Create (opcode, target); + } + + public Instruction Create (OpCode opcode, Instruction [] targets) + { + return Instruction.Create (opcode, targets); + } + + public Instruction Create (OpCode opcode, VariableDefinition variable) + { + return Instruction.Create (opcode, variable); + } + + public Instruction Create (OpCode opcode, ParameterDefinition parameter) + { + return Instruction.Create (opcode, parameter); + } + + public void Emit (OpCode opcode) + { + Append (Create (opcode)); + } + + public void Emit (OpCode opcode, TypeReference type) + { + Append (Create (opcode, type)); + } + + public void Emit (OpCode opcode, MethodReference method) + { + Append (Create (opcode, method)); + } + + public void Emit (OpCode opcode, CallSite site) + { + Append (Create (opcode, site)); + } + + public void Emit (OpCode opcode, FieldReference field) + { + Append (Create (opcode, field)); + } + + public void Emit (OpCode opcode, string value) + { + Append (Create (opcode, value)); + } + + public void Emit (OpCode opcode, byte value) + { + Append (Create (opcode, value)); + } + + public void Emit (OpCode opcode, sbyte value) + { + Append (Create (opcode, value)); + } + + public void Emit (OpCode opcode, int value) + { + Append (Create (opcode, value)); + } + + public void Emit (OpCode opcode, long value) + { + Append (Create (opcode, value)); + } + + public void Emit (OpCode opcode, float value) + { + Append (Create (opcode, value)); + } + + public void Emit (OpCode opcode, double value) + { + Append (Create (opcode, value)); + } + + public void Emit (OpCode opcode, Instruction target) + { + Append (Create (opcode, target)); + } + + public void Emit (OpCode opcode, Instruction [] targets) + { + Append (Create (opcode, targets)); + } + + public void Emit (OpCode opcode, VariableDefinition variable) + { + Append (Create (opcode, variable)); + } + + public void Emit (OpCode opcode, ParameterDefinition parameter) + { + Append (Create (opcode, parameter)); + } + + public void InsertBefore (Instruction target, Instruction instruction) + { + if (target == null) + throw new ArgumentNullException ("target"); + if (instruction == null) + throw new ArgumentNullException ("instruction"); + + var index = instructions.IndexOf (target); + if (index == -1) + throw new ArgumentOutOfRangeException ("target"); + + instructions.Insert (index, instruction); + } + + public void InsertAfter (Instruction target, Instruction instruction) + { + if (target == null) + throw new ArgumentNullException ("target"); + if (instruction == null) + throw new ArgumentNullException ("instruction"); + + var index = instructions.IndexOf (target); + if (index == -1) + throw new ArgumentOutOfRangeException ("target"); + + instructions.Insert (index + 1, instruction); + } + + public void Append (Instruction instruction) + { + if (instruction == null) + throw new ArgumentNullException ("instruction"); + + instructions.Add (instruction); + } + + public void Replace (Instruction target, Instruction instruction) + { + if (target == null) + throw new ArgumentNullException ("target"); + if (instruction == null) + throw new ArgumentNullException ("instruction"); + + InsertAfter (target, instruction); + Remove (target); + } + + public void Remove (Instruction instruction) + { + if (instruction == null) + throw new ArgumentNullException ("instruction"); + + if (!instructions.Remove (instruction)) + throw new ArgumentOutOfRangeException ("instruction"); + } + } +} diff --git a/Mono.Cecil.Cil/Instruction.cs b/Mono.Cecil.Cil/Instruction.cs new file mode 100644 index 000000000..e8d36c4b3 --- /dev/null +++ b/Mono.Cecil.Cil/Instruction.cs @@ -0,0 +1,321 @@ +// +// Instruction.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Text; + +namespace Mono.Cecil.Cil { + + public sealed class Instruction { + + internal int offset; + internal OpCode opcode; + internal object operand; + + internal Instruction previous; + internal Instruction next; + + SequencePoint sequence_point; + + public int Offset { + get { return offset; } + set { offset = value; } + } + + public OpCode OpCode { + get { return opcode; } + set { opcode = value; } + } + + public object Operand { + get { return operand; } + set { operand = value; } + } + + public Instruction Previous { + get { return previous; } + set { previous = value; } + } + + public Instruction Next { + get { return next; } + set { next = value; } + } + + public SequencePoint SequencePoint { + get { return sequence_point; } + set { sequence_point = value; } + } + + internal Instruction (int offset, OpCode opCode) + { + this.offset = offset; + this.opcode = opCode; + } + + internal Instruction (OpCode opcode, object operand) + { + this.opcode = opcode; + this.operand = operand; + } + + public int GetSize () + { + int size = opcode.Size; + + switch (opcode.OperandType) { + case OperandType.InlineSwitch: + return size + (1 + ((Instruction []) operand).Length) * 4; + case OperandType.InlineI8: + case OperandType.InlineR: + return size + 8; + case OperandType.InlineBrTarget: + case OperandType.InlineField: + case OperandType.InlineI: + case OperandType.InlineMethod: + case OperandType.InlineString: + case OperandType.InlineTok: + case OperandType.InlineType: + case OperandType.ShortInlineR: + case OperandType.InlineSig: + return size + 4; + case OperandType.InlineArg: + case OperandType.InlineVar: + return size + 2; + case OperandType.ShortInlineBrTarget: + case OperandType.ShortInlineI: + case OperandType.ShortInlineArg: + case OperandType.ShortInlineVar: + return size + 1; + default: + return size; + } + } + + public override string ToString () + { + var instruction = new StringBuilder (); + + AppendLabel (instruction, this); + instruction.Append (':'); + instruction.Append (' '); + instruction.Append (opcode.Name); + + if (operand == null) + return instruction.ToString (); + + instruction.Append (' '); + + switch (opcode.OperandType) { + case OperandType.ShortInlineBrTarget: + case OperandType.InlineBrTarget: + AppendLabel (instruction, (Instruction) operand); + break; + case OperandType.InlineSwitch: + var labels = (Instruction []) operand; + for (int i = 0; i < labels.Length; i++) { + if (i > 0) + instruction.Append (','); + + AppendLabel (instruction, labels [i]); + } + break; + case OperandType.InlineString: + instruction.Append ('\"'); + instruction.Append (operand); + instruction.Append ('\"'); + break; + default: + instruction.Append (operand); + break; + } + + return instruction.ToString (); + } + + static void AppendLabel (StringBuilder builder, Instruction instruction) + { + builder.Append ("IL_"); + builder.Append (instruction.offset.ToString ("x4")); + } + + public static Instruction Create (OpCode opcode) + { + if (opcode.OperandType != OperandType.InlineNone) + throw new ArgumentException ("opcode"); + + return new Instruction (opcode, null); + } + + public static Instruction Create (OpCode opcode, TypeReference type) + { + if (type == null) + throw new ArgumentNullException ("type"); + if (opcode.OperandType != OperandType.InlineType && + opcode.OperandType != OperandType.InlineTok) + throw new ArgumentException ("opcode"); + + return new Instruction (opcode, type); + } + + public static Instruction Create (OpCode opcode, CallSite site) + { + if (site == null) + throw new ArgumentNullException ("site"); + if (opcode.Code != Code.Calli) + throw new ArgumentException ("code"); + + return new Instruction (opcode, site); + } + + public static Instruction Create (OpCode opcode, MethodReference method) + { + if (method == null) + throw new ArgumentNullException ("method"); + if (opcode.OperandType != OperandType.InlineMethod && + opcode.OperandType != OperandType.InlineTok) + throw new ArgumentException ("opcode"); + + return new Instruction (opcode, method); + } + + public static Instruction Create (OpCode opcode, FieldReference field) + { + if (field == null) + throw new ArgumentNullException ("field"); + if (opcode.OperandType != OperandType.InlineField && + opcode.OperandType != OperandType.InlineTok) + throw new ArgumentException ("opcode"); + + return new Instruction (opcode, field); + } + + public static Instruction Create (OpCode opcode, string value) + { + if (value == null) + throw new ArgumentNullException ("value"); + if (opcode.OperandType != OperandType.InlineString) + throw new ArgumentException ("opcode"); + + return new Instruction (opcode, value); + } + + public static Instruction Create (OpCode opcode, sbyte value) + { + if (opcode.OperandType != OperandType.ShortInlineI && + opcode != OpCodes.Ldc_I4_S) + throw new ArgumentException ("opcode"); + + return new Instruction (opcode, value); + } + + public static Instruction Create (OpCode opcode, byte value) + { + if (opcode.OperandType != OperandType.ShortInlineI || + opcode == OpCodes.Ldc_I4_S) + throw new ArgumentException ("opcode"); + + return new Instruction (opcode, value); + } + + public static Instruction Create (OpCode opcode, int value) + { + if (opcode.OperandType != OperandType.InlineI) + throw new ArgumentException ("opcode"); + + return new Instruction (opcode, value); + } + + public static Instruction Create (OpCode opcode, long value) + { + if (opcode.OperandType != OperandType.InlineI8) + throw new ArgumentException ("opcode"); + + return new Instruction (opcode, value); + } + + public static Instruction Create (OpCode opcode, float value) + { + if (opcode.OperandType != OperandType.ShortInlineR) + throw new ArgumentException ("opcode"); + + return new Instruction (opcode, value); + } + + public static Instruction Create (OpCode opcode, double value) + { + if (opcode.OperandType != OperandType.InlineR) + throw new ArgumentException ("opcode"); + + return new Instruction (opcode, value); + } + + public static Instruction Create (OpCode opcode, Instruction target) + { + if (target == null) + throw new ArgumentNullException ("target"); + if (opcode.OperandType != OperandType.InlineBrTarget && + opcode.OperandType != OperandType.ShortInlineBrTarget) + throw new ArgumentException ("opcode"); + + return new Instruction (opcode, target); + } + + public static Instruction Create (OpCode opcode, Instruction [] targets) + { + if (targets == null) + throw new ArgumentNullException ("targets"); + if (opcode.OperandType != OperandType.InlineSwitch) + throw new ArgumentException ("opcode"); + + return new Instruction (opcode, targets); + } + + public static Instruction Create (OpCode opcode, VariableDefinition variable) + { + if (variable == null) + throw new ArgumentNullException ("variable"); + if (opcode.OperandType != OperandType.ShortInlineVar && + opcode.OperandType != OperandType.InlineVar) + throw new ArgumentException ("opcode"); + + return new Instruction (opcode, variable); + } + + public static Instruction Create (OpCode opcode, ParameterDefinition parameter) + { + if (parameter == null) + throw new ArgumentNullException ("parameter"); + if (opcode.OperandType != OperandType.ShortInlineArg && + opcode.OperandType != OperandType.InlineArg) + throw new ArgumentException ("opcode"); + + return new Instruction (opcode, parameter); + } + } +} diff --git a/Mono.Cecil.Cil/MethodBody.cs b/Mono.Cecil.Cil/MethodBody.cs new file mode 100644 index 000000000..b57900e5a --- /dev/null +++ b/Mono.Cecil.Cil/MethodBody.cs @@ -0,0 +1,230 @@ +// +// MethodBody.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +using Mono.Collections.Generic; + +namespace Mono.Cecil.Cil { + + public sealed class MethodBody : IVariableDefinitionProvider { + + readonly internal MethodDefinition method; + + internal ParameterDefinition this_parameter; + internal int max_stack_size; + internal int code_size; + internal bool init_locals; + internal MetadataToken local_var_token; + + internal Collection instructions; + internal Collection exceptions; + internal Collection variables; + Scope scope; + + public MethodDefinition Method { + get { return method; } + } + + public int MaxStackSize { + get { return max_stack_size; } + set { max_stack_size = value; } + } + + public int CodeSize { + get { return code_size; } + } + + public bool InitLocals { + get { return init_locals; } + set { init_locals = value; } + } + + public MetadataToken LocalVarToken { + get { return local_var_token; } + set { local_var_token = value; } + } + + public Collection Instructions { + get { return instructions ?? (instructions = new InstructionCollection ()); } + } + + public bool HasExceptionHandlers { + get { return !exceptions.IsNullOrEmpty (); } + } + + public Collection ExceptionHandlers { + get { return exceptions ?? (exceptions = new Collection ()); } + } + + public bool HasVariables { + get { return !variables.IsNullOrEmpty (); } + } + + public Collection Variables { + get { return variables ?? (variables = new VariableDefinitionCollection ()); } + } + + public Scope Scope { + get { return scope; } + set { scope = value; } + } + + public ParameterDefinition ThisParameter { + get { + if (method == null || method.DeclaringType == null) + throw new NotSupportedException (); + + return this_parameter ?? (this_parameter = new ParameterDefinition ("0", ParameterAttributes.None, method.DeclaringType)); + } + } + + public MethodBody (MethodDefinition method) + { + this.method = method; + } + + public ILProcessor GetILProcessor () + { + return new ILProcessor (this); + } + } + + public interface IVariableDefinitionProvider { + bool HasVariables { get; } + Collection Variables { get; } + } + + class VariableDefinitionCollection : Collection { + + internal VariableDefinitionCollection () + { + } + + internal VariableDefinitionCollection (int capacity) + : base (capacity) + { + } + + protected override void OnAdd (VariableDefinition item, int index) + { + item.index = index; + } + + protected override void OnInsert (VariableDefinition item, int index) + { + item.index = index; + + for (int i = index; i < size; i++) + items [i].index = i + 1; + } + + protected override void OnSet (VariableDefinition item, int index) + { + item.index = index; + } + + protected override void OnRemove (VariableDefinition item, int index) + { + item.index = -1; + + for (int i = index + 1; i < size; i++) + items [i].index = i - 1; + } + } + + class InstructionCollection : Collection { + + internal InstructionCollection () + { + } + + internal InstructionCollection (int capacity) + : base (capacity) + { + } + + protected override void OnAdd (Instruction item, int index) + { + if (index == 0) + return; + + var previous = items [index - 1]; + previous.next = item; + item.previous = previous; + } + + protected override void OnInsert (Instruction item, int index) + { + if (size == 0) + return; + + var current = items [index]; + if (current == null) { + var last = items [index - 1]; + last.next = item; + item.previous = last; + return; + } + + var previous = current.previous; + if (previous != null) { + previous.next = item; + item.previous = previous; + } + + current.previous = item; + item.next = current; + } + + protected override void OnSet (Instruction item, int index) + { + var current = items [index]; + + item.previous = current.previous; + item.next = current.next; + + current.previous = null; + current.next = null; + } + + protected override void OnRemove (Instruction item, int index) + { + var previous = item.previous; + if (previous != null) + previous.next = item.next; + + var next = item.next; + if (next != null) + next.previous = item.previous; + + item.previous = null; + item.next = null; + } + } +} diff --git a/Mono.Cecil.Cil/OpCode.cs b/Mono.Cecil.Cil/OpCode.cs new file mode 100644 index 000000000..aad4ba4b9 --- /dev/null +++ b/Mono.Cecil.Cil/OpCode.cs @@ -0,0 +1,524 @@ +// +// OpCode.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace Mono.Cecil.Cil { + + public enum FlowControl { + Branch, + Break, + Call, + Cond_Branch, + Meta, + Next, + Phi, + Return, + Throw, + } + + public enum OpCodeType { + Annotation, + Macro, + Nternal, + Objmodel, + Prefix, + Primitive, + } + + public enum OperandType { + InlineBrTarget, + InlineField, + InlineI, + InlineI8, + InlineMethod, + InlineNone, + InlinePhi, + InlineR, + InlineSig, + InlineString, + InlineSwitch, + InlineTok, + InlineType, + InlineVar, + InlineArg, + ShortInlineBrTarget, + ShortInlineI, + ShortInlineR, + ShortInlineVar, + ShortInlineArg, + } + + public enum StackBehaviour { + Pop0, + Pop1, + Pop1_pop1, + Popi, + Popi_pop1, + Popi_popi, + Popi_popi8, + Popi_popi_popi, + Popi_popr4, + Popi_popr8, + Popref, + Popref_pop1, + Popref_popi, + Popref_popi_popi, + Popref_popi_popi8, + Popref_popi_popr4, + Popref_popi_popr8, + Popref_popi_popref, + PopAll, + Push0, + Push1, + Push1_push1, + Pushi, + Pushi8, + Pushr4, + Pushr8, + Pushref, + Varpop, + Varpush, + } + + public struct OpCode { + + readonly byte op1; + readonly byte op2; + readonly byte code; + readonly byte flow_control; + readonly byte opcode_type; + readonly byte operand_type; + readonly byte stack_behavior_pop; + readonly byte stack_behavior_push; + + public string Name { + get { return OpCodeNames.names [op1 == 0xff ? op2 : op2 + 256]; } + } + + public int Size { + get { return op1 == 0xff ? 1 : 2; } + } + + public byte Op1 { + get { return op1; } + } + + public byte Op2 { + get { return op2; } + } + + public short Value { + get { return (short) ((op1 << 8) | op2); } + } + + public Code Code { + get { return (Code) code; } + } + + public FlowControl FlowControl { + get { return (FlowControl) flow_control; } + } + + public OpCodeType OpCodeType { + get { return (OpCodeType) opcode_type; } + } + + public OperandType OperandType { + get { return (OperandType) operand_type; } + } + + public StackBehaviour StackBehaviourPop { + get { return (StackBehaviour) stack_behavior_pop; } + } + + public StackBehaviour StackBehaviourPush { + get { return (StackBehaviour) stack_behavior_push; } + } + + internal OpCode (int x, int y) + { + this.op1 = (byte) ((x >> 0) & 0xff); + this.op2 = (byte) ((x >> 8) & 0xff); + this.code = (byte) ((x >> 16) & 0xff); + this.flow_control = (byte) ((x >> 24) & 0xff); + + this.opcode_type = (byte) ((y >> 0) & 0xff); + this.operand_type = (byte) ((y >> 8) & 0xff); + this.stack_behavior_pop = (byte) ((y >> 16) & 0xff); + this.stack_behavior_push = (byte) ((y >> 24) & 0xff); + + if (op1 == 0xff) + OpCodes.OneByteOpCode [op2] = this; + else + OpCodes.TwoBytesOpCode [op2] = this; + } + + public override int GetHashCode () + { + return Value; + } + + public override bool Equals (object obj) + { + if (!(obj is OpCode)) + return false; + + var opcode = (OpCode) obj; + return op1 == opcode.op1 && op2 == opcode.op2; + } + + public bool Equals (OpCode opcode) + { + return op1 == opcode.op1 && op2 == opcode.op2; + } + + public static bool operator == (OpCode one, OpCode other) + { + return one.op1 == other.op1 && one.op2 == other.op2; + } + + public static bool operator != (OpCode one, OpCode other) + { + return one.op1 != other.op1 || one.op2 != other.op2; + } + + public override string ToString () + { + return Name; + } + } + + static class OpCodeNames { + + internal static readonly string [] names = { + "nop", + "break", + "ldarg.0", + "ldarg.1", + "ldarg.2", + "ldarg.3", + "ldloc.0", + "ldloc.1", + "ldloc.2", + "ldloc.3", + "stloc.0", + "stloc.1", + "stloc.2", + "stloc.3", + "ldarg.s", + "ldarga.s", + "starg.s", + "ldloc.s", + "ldloca.s", + "stloc.s", + "ldnull", + "ldc.i4.m1", + "ldc.i4.0", + "ldc.i4.1", + "ldc.i4.2", + "ldc.i4.3", + "ldc.i4.4", + "ldc.i4.5", + "ldc.i4.6", + "ldc.i4.7", + "ldc.i4.8", + "ldc.i4.s", + "ldc.i4", + "ldc.i8", + "ldc.r4", + "ldc.r8", + null, + "dup", + "pop", + "jmp", + "call", + "calli", + "ret", + "br.s", + "brfalse.s", + "brtrue.s", + "beq.s", + "bge.s", + "bgt.s", + "ble.s", + "blt.s", + "bne.un.s", + "bge.un.s", + "bgt.un.s", + "ble.un.s", + "blt.un.s", + "br", + "brfalse", + "brtrue", + "beq", + "bge", + "bgt", + "ble", + "blt", + "bne.un", + "bge.un", + "bgt.un", + "ble.un", + "blt.un", + "switch", + "ldind.i1", + "ldind.u1", + "ldind.i2", + "ldind.u2", + "ldind.i4", + "ldind.u4", + "ldind.i8", + "ldind.i", + "ldind.r4", + "ldind.r8", + "ldind.ref", + "stind.ref", + "stind.i1", + "stind.i2", + "stind.i4", + "stind.i8", + "stind.r4", + "stind.r8", + "add", + "sub", + "mul", + "div", + "div.un", + "rem", + "rem.un", + "and", + "or", + "xor", + "shl", + "shr", + "shr.un", + "neg", + "not", + "conv.i1", + "conv.i2", + "conv.i4", + "conv.i8", + "conv.r4", + "conv.r8", + "conv.u4", + "conv.u8", + "callvirt", + "cpobj", + "ldobj", + "ldstr", + "newobj", + "castclass", + "isinst", + "conv.r.un", + null, + null, + "unbox", + "throw", + "ldfld", + "ldflda", + "stfld", + "ldsfld", + "ldsflda", + "stsfld", + "stobj", + "conv.ovf.i1.un", + "conv.ovf.i2.un", + "conv.ovf.i4.un", + "conv.ovf.i8.un", + "conv.ovf.u1.un", + "conv.ovf.u2.un", + "conv.ovf.u4.un", + "conv.ovf.u8.un", + "conv.ovf.i.un", + "conv.ovf.u.un", + "box", + "newarr", + "ldlen", + "ldelema", + "ldelem.i1", + "ldelem.u1", + "ldelem.i2", + "ldelem.u2", + "ldelem.i4", + "ldelem.u4", + "ldelem.i8", + "ldelem.i", + "ldelem.r4", + "ldelem.r8", + "ldelem.ref", + "stelem.i", + "stelem.i1", + "stelem.i2", + "stelem.i4", + "stelem.i8", + "stelem.r4", + "stelem.r8", + "stelem.ref", + "ldelem.any", + "stelem.any", + "unbox.any", + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + "conv.ovf.i1", + "conv.ovf.u1", + "conv.ovf.i2", + "conv.ovf.u2", + "conv.ovf.i4", + "conv.ovf.u4", + "conv.ovf.i8", + "conv.ovf.u8", + null, + null, + null, + null, + null, + null, + null, + "refanyval", + "ckfinite", + null, + null, + "mkrefany", + null, + null, + null, + null, + null, + null, + null, + null, + null, + "ldtoken", + "conv.u2", + "conv.u1", + "conv.i", + "conv.ovf.i", + "conv.ovf.u", + "add.ovf", + "add.ovf.un", + "mul.ovf", + "mul.ovf.un", + "sub.ovf", + "sub.ovf.un", + "endfinally", + "leave", + "leave.s", + "stind.i", + "conv.u", + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + "prefix7", + "prefix6", + "prefix5", + "prefix4", + "prefix3", + "prefix2", + "prefix1", + "prefixref", + "arglist", + "ceq", + "cgt", + "cgt.un", + "clt", + "clt.un", + "ldftn", + "ldvirtftn", + null, + "ldarg", + "ldarga", + "starg", + "ldloc", + "ldloca", + "stloc", + "localloc", + null, + "endfilter", + "unaligned.", + "volatile.", + "tail.", + "initobj", + "constrained.", + "cpblk", + "initblk", + "no.", // added by spouliot to match Cecil existing definitions + "rethrow", + null, + "sizeof", + "refanytype", + "readonly.", // added by spouliot to match Cecil existing definitions + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + }; + } +} diff --git a/Mono.Cecil.Cil/OpCodes.cs b/Mono.Cecil.Cil/OpCodes.cs new file mode 100644 index 000000000..ce468a19c --- /dev/null +++ b/Mono.Cecil.Cil/OpCodes.cs @@ -0,0 +1,912 @@ +// +// OpCodes.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace Mono.Cecil.Cil { + + public static class OpCodes { + + internal static readonly OpCode [] OneByteOpCode = new OpCode [0xe0 + 1]; + internal static readonly OpCode [] TwoBytesOpCode = new OpCode [0x1e + 1]; + + public static readonly OpCode Nop = new OpCode ( + 0xff << 0 | 0x00 << 8 | (byte) Code.Nop << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Break = new OpCode ( + 0xff << 0 | 0x01 << 8 | (byte) Code.Break << 16 | (byte) FlowControl.Break << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Ldarg_0 = new OpCode ( + 0xff << 0 | 0x02 << 8 | (byte) Code.Ldarg_0 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Push1 << 24); + + public static readonly OpCode Ldarg_1 = new OpCode ( + 0xff << 0 | 0x03 << 8 | (byte) Code.Ldarg_1 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Push1 << 24); + + public static readonly OpCode Ldarg_2 = new OpCode ( + 0xff << 0 | 0x04 << 8 | (byte) Code.Ldarg_2 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Push1 << 24); + + public static readonly OpCode Ldarg_3 = new OpCode ( + 0xff << 0 | 0x05 << 8 | (byte) Code.Ldarg_3 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Push1 << 24); + + public static readonly OpCode Ldloc_0 = new OpCode ( + 0xff << 0 | 0x06 << 8 | (byte) Code.Ldloc_0 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Push1 << 24); + + public static readonly OpCode Ldloc_1 = new OpCode ( + 0xff << 0 | 0x07 << 8 | (byte) Code.Ldloc_1 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Push1 << 24); + + public static readonly OpCode Ldloc_2 = new OpCode ( + 0xff << 0 | 0x08 << 8 | (byte) Code.Ldloc_2 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Push1 << 24); + + public static readonly OpCode Ldloc_3 = new OpCode ( + 0xff << 0 | 0x09 << 8 | (byte) Code.Ldloc_3 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Push1 << 24); + + public static readonly OpCode Stloc_0 = new OpCode ( + 0xff << 0 | 0x0a << 8 | (byte) Code.Stloc_0 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Stloc_1 = new OpCode ( + 0xff << 0 | 0x0b << 8 | (byte) Code.Stloc_1 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Stloc_2 = new OpCode ( + 0xff << 0 | 0x0c << 8 | (byte) Code.Stloc_2 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Stloc_3 = new OpCode ( + 0xff << 0 | 0x0d << 8 | (byte) Code.Stloc_3 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Ldarg_S = new OpCode ( + 0xff << 0 | 0x0e << 8 | (byte) Code.Ldarg_S << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.ShortInlineArg << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Push1 << 24); + + public static readonly OpCode Ldarga_S = new OpCode ( + 0xff << 0 | 0x0f << 8 | (byte) Code.Ldarga_S << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.ShortInlineArg << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Starg_S = new OpCode ( + 0xff << 0 | 0x10 << 8 | (byte) Code.Starg_S << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.ShortInlineArg << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Ldloc_S = new OpCode ( + 0xff << 0 | 0x11 << 8 | (byte) Code.Ldloc_S << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.ShortInlineVar << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Push1 << 24); + + public static readonly OpCode Ldloca_S = new OpCode ( + 0xff << 0 | 0x12 << 8 | (byte) Code.Ldloca_S << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.ShortInlineVar << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Stloc_S = new OpCode ( + 0xff << 0 | 0x13 << 8 | (byte) Code.Stloc_S << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.ShortInlineVar << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Ldnull = new OpCode ( + 0xff << 0 | 0x14 << 8 | (byte) Code.Ldnull << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Pushref << 24); + + public static readonly OpCode Ldc_I4_M1 = new OpCode ( + 0xff << 0 | 0x15 << 8 | (byte) Code.Ldc_I4_M1 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldc_I4_0 = new OpCode ( + 0xff << 0 | 0x16 << 8 | (byte) Code.Ldc_I4_0 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldc_I4_1 = new OpCode ( + 0xff << 0 | 0x17 << 8 | (byte) Code.Ldc_I4_1 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldc_I4_2 = new OpCode ( + 0xff << 0 | 0x18 << 8 | (byte) Code.Ldc_I4_2 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldc_I4_3 = new OpCode ( + 0xff << 0 | 0x19 << 8 | (byte) Code.Ldc_I4_3 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldc_I4_4 = new OpCode ( + 0xff << 0 | 0x1a << 8 | (byte) Code.Ldc_I4_4 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldc_I4_5 = new OpCode ( + 0xff << 0 | 0x1b << 8 | (byte) Code.Ldc_I4_5 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldc_I4_6 = new OpCode ( + 0xff << 0 | 0x1c << 8 | (byte) Code.Ldc_I4_6 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldc_I4_7 = new OpCode ( + 0xff << 0 | 0x1d << 8 | (byte) Code.Ldc_I4_7 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldc_I4_8 = new OpCode ( + 0xff << 0 | 0x1e << 8 | (byte) Code.Ldc_I4_8 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldc_I4_S = new OpCode ( + 0xff << 0 | 0x1f << 8 | (byte) Code.Ldc_I4_S << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.ShortInlineI << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldc_I4 = new OpCode ( + 0xff << 0 | 0x20 << 8 | (byte) Code.Ldc_I4 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineI << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldc_I8 = new OpCode ( + 0xff << 0 | 0x21 << 8 | (byte) Code.Ldc_I8 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineI8 << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Pushi8 << 24); + + public static readonly OpCode Ldc_R4 = new OpCode ( + 0xff << 0 | 0x22 << 8 | (byte) Code.Ldc_R4 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.ShortInlineR << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Pushr4 << 24); + + public static readonly OpCode Ldc_R8 = new OpCode ( + 0xff << 0 | 0x23 << 8 | (byte) Code.Ldc_R8 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineR << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Pushr8 << 24); + + public static readonly OpCode Dup = new OpCode ( + 0xff << 0 | 0x25 << 8 | (byte) Code.Dup << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Push1_push1 << 24); + + public static readonly OpCode Pop = new OpCode ( + 0xff << 0 | 0x26 << 8 | (byte) Code.Pop << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Jmp = new OpCode ( + 0xff << 0 | 0x27 << 8 | (byte) Code.Jmp << 16 | (byte) FlowControl.Call << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineMethod << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Call = new OpCode ( + 0xff << 0 | 0x28 << 8 | (byte) Code.Call << 16 | (byte) FlowControl.Call << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineMethod << 8 | (byte) StackBehaviour.Varpop << 16 | (byte) StackBehaviour.Varpush << 24); + + public static readonly OpCode Calli = new OpCode ( + 0xff << 0 | 0x29 << 8 | (byte) Code.Calli << 16 | (byte) FlowControl.Call << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineSig << 8 | (byte) StackBehaviour.Varpop << 16 | (byte) StackBehaviour.Varpush << 24); + + public static readonly OpCode Ret = new OpCode ( + 0xff << 0 | 0x2a << 8 | (byte) Code.Ret << 16 | (byte) FlowControl.Return << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Varpop << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Br_S = new OpCode ( + 0xff << 0 | 0x2b << 8 | (byte) Code.Br_S << 16 | (byte) FlowControl.Branch << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.ShortInlineBrTarget << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Brfalse_S = new OpCode ( + 0xff << 0 | 0x2c << 8 | (byte) Code.Brfalse_S << 16 | (byte) FlowControl.Cond_Branch << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.ShortInlineBrTarget << 8 | (byte) StackBehaviour.Popi << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Brtrue_S = new OpCode ( + 0xff << 0 | 0x2d << 8 | (byte) Code.Brtrue_S << 16 | (byte) FlowControl.Cond_Branch << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.ShortInlineBrTarget << 8 | (byte) StackBehaviour.Popi << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Beq_S = new OpCode ( + 0xff << 0 | 0x2e << 8 | (byte) Code.Beq_S << 16 | (byte) FlowControl.Cond_Branch << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.ShortInlineBrTarget << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Bge_S = new OpCode ( + 0xff << 0 | 0x2f << 8 | (byte) Code.Bge_S << 16 | (byte) FlowControl.Cond_Branch << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.ShortInlineBrTarget << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Bgt_S = new OpCode ( + 0xff << 0 | 0x30 << 8 | (byte) Code.Bgt_S << 16 | (byte) FlowControl.Cond_Branch << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.ShortInlineBrTarget << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Ble_S = new OpCode ( + 0xff << 0 | 0x31 << 8 | (byte) Code.Ble_S << 16 | (byte) FlowControl.Cond_Branch << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.ShortInlineBrTarget << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Blt_S = new OpCode ( + 0xff << 0 | 0x32 << 8 | (byte) Code.Blt_S << 16 | (byte) FlowControl.Cond_Branch << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.ShortInlineBrTarget << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Bne_Un_S = new OpCode ( + 0xff << 0 | 0x33 << 8 | (byte) Code.Bne_Un_S << 16 | (byte) FlowControl.Cond_Branch << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.ShortInlineBrTarget << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Bge_Un_S = new OpCode ( + 0xff << 0 | 0x34 << 8 | (byte) Code.Bge_Un_S << 16 | (byte) FlowControl.Cond_Branch << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.ShortInlineBrTarget << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Bgt_Un_S = new OpCode ( + 0xff << 0 | 0x35 << 8 | (byte) Code.Bgt_Un_S << 16 | (byte) FlowControl.Cond_Branch << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.ShortInlineBrTarget << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Ble_Un_S = new OpCode ( + 0xff << 0 | 0x36 << 8 | (byte) Code.Ble_Un_S << 16 | (byte) FlowControl.Cond_Branch << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.ShortInlineBrTarget << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Blt_Un_S = new OpCode ( + 0xff << 0 | 0x37 << 8 | (byte) Code.Blt_Un_S << 16 | (byte) FlowControl.Cond_Branch << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.ShortInlineBrTarget << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Br = new OpCode ( + 0xff << 0 | 0x38 << 8 | (byte) Code.Br << 16 | (byte) FlowControl.Branch << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineBrTarget << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Brfalse = new OpCode ( + 0xff << 0 | 0x39 << 8 | (byte) Code.Brfalse << 16 | (byte) FlowControl.Cond_Branch << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineBrTarget << 8 | (byte) StackBehaviour.Popi << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Brtrue = new OpCode ( + 0xff << 0 | 0x3a << 8 | (byte) Code.Brtrue << 16 | (byte) FlowControl.Cond_Branch << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineBrTarget << 8 | (byte) StackBehaviour.Popi << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Beq = new OpCode ( + 0xff << 0 | 0x3b << 8 | (byte) Code.Beq << 16 | (byte) FlowControl.Cond_Branch << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.InlineBrTarget << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Bge = new OpCode ( + 0xff << 0 | 0x3c << 8 | (byte) Code.Bge << 16 | (byte) FlowControl.Cond_Branch << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.InlineBrTarget << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Bgt = new OpCode ( + 0xff << 0 | 0x3d << 8 | (byte) Code.Bgt << 16 | (byte) FlowControl.Cond_Branch << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.InlineBrTarget << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Ble = new OpCode ( + 0xff << 0 | 0x3e << 8 | (byte) Code.Ble << 16 | (byte) FlowControl.Cond_Branch << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.InlineBrTarget << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Blt = new OpCode ( + 0xff << 0 | 0x3f << 8 | (byte) Code.Blt << 16 | (byte) FlowControl.Cond_Branch << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.InlineBrTarget << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Bne_Un = new OpCode ( + 0xff << 0 | 0x40 << 8 | (byte) Code.Bne_Un << 16 | (byte) FlowControl.Cond_Branch << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.InlineBrTarget << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Bge_Un = new OpCode ( + 0xff << 0 | 0x41 << 8 | (byte) Code.Bge_Un << 16 | (byte) FlowControl.Cond_Branch << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.InlineBrTarget << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Bgt_Un = new OpCode ( + 0xff << 0 | 0x42 << 8 | (byte) Code.Bgt_Un << 16 | (byte) FlowControl.Cond_Branch << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.InlineBrTarget << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Ble_Un = new OpCode ( + 0xff << 0 | 0x43 << 8 | (byte) Code.Ble_Un << 16 | (byte) FlowControl.Cond_Branch << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.InlineBrTarget << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Blt_Un = new OpCode ( + 0xff << 0 | 0x44 << 8 | (byte) Code.Blt_Un << 16 | (byte) FlowControl.Cond_Branch << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.InlineBrTarget << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Switch = new OpCode ( + 0xff << 0 | 0x45 << 8 | (byte) Code.Switch << 16 | (byte) FlowControl.Cond_Branch << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineSwitch << 8 | (byte) StackBehaviour.Popi << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Ldind_I1 = new OpCode ( + 0xff << 0 | 0x46 << 8 | (byte) Code.Ldind_I1 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popi << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldind_U1 = new OpCode ( + 0xff << 0 | 0x47 << 8 | (byte) Code.Ldind_U1 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popi << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldind_I2 = new OpCode ( + 0xff << 0 | 0x48 << 8 | (byte) Code.Ldind_I2 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popi << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldind_U2 = new OpCode ( + 0xff << 0 | 0x49 << 8 | (byte) Code.Ldind_U2 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popi << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldind_I4 = new OpCode ( + 0xff << 0 | 0x4a << 8 | (byte) Code.Ldind_I4 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popi << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldind_U4 = new OpCode ( + 0xff << 0 | 0x4b << 8 | (byte) Code.Ldind_U4 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popi << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldind_I8 = new OpCode ( + 0xff << 0 | 0x4c << 8 | (byte) Code.Ldind_I8 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popi << 16 | (byte) StackBehaviour.Pushi8 << 24); + + public static readonly OpCode Ldind_I = new OpCode ( + 0xff << 0 | 0x4d << 8 | (byte) Code.Ldind_I << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popi << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldind_R4 = new OpCode ( + 0xff << 0 | 0x4e << 8 | (byte) Code.Ldind_R4 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popi << 16 | (byte) StackBehaviour.Pushr4 << 24); + + public static readonly OpCode Ldind_R8 = new OpCode ( + 0xff << 0 | 0x4f << 8 | (byte) Code.Ldind_R8 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popi << 16 | (byte) StackBehaviour.Pushr8 << 24); + + public static readonly OpCode Ldind_Ref = new OpCode ( + 0xff << 0 | 0x50 << 8 | (byte) Code.Ldind_Ref << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popi << 16 | (byte) StackBehaviour.Pushref << 24); + + public static readonly OpCode Stind_Ref = new OpCode ( + 0xff << 0 | 0x51 << 8 | (byte) Code.Stind_Ref << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popi_popi << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Stind_I1 = new OpCode ( + 0xff << 0 | 0x52 << 8 | (byte) Code.Stind_I1 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popi_popi << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Stind_I2 = new OpCode ( + 0xff << 0 | 0x53 << 8 | (byte) Code.Stind_I2 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popi_popi << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Stind_I4 = new OpCode ( + 0xff << 0 | 0x54 << 8 | (byte) Code.Stind_I4 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popi_popi << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Stind_I8 = new OpCode ( + 0xff << 0 | 0x55 << 8 | (byte) Code.Stind_I8 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popi_popi8 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Stind_R4 = new OpCode ( + 0xff << 0 | 0x56 << 8 | (byte) Code.Stind_R4 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popi_popr4 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Stind_R8 = new OpCode ( + 0xff << 0 | 0x57 << 8 | (byte) Code.Stind_R8 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popi_popr8 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Add = new OpCode ( + 0xff << 0 | 0x58 << 8 | (byte) Code.Add << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Push1 << 24); + + public static readonly OpCode Sub = new OpCode ( + 0xff << 0 | 0x59 << 8 | (byte) Code.Sub << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Push1 << 24); + + public static readonly OpCode Mul = new OpCode ( + 0xff << 0 | 0x5a << 8 | (byte) Code.Mul << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Push1 << 24); + + public static readonly OpCode Div = new OpCode ( + 0xff << 0 | 0x5b << 8 | (byte) Code.Div << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Push1 << 24); + + public static readonly OpCode Div_Un = new OpCode ( + 0xff << 0 | 0x5c << 8 | (byte) Code.Div_Un << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Push1 << 24); + + public static readonly OpCode Rem = new OpCode ( + 0xff << 0 | 0x5d << 8 | (byte) Code.Rem << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Push1 << 24); + + public static readonly OpCode Rem_Un = new OpCode ( + 0xff << 0 | 0x5e << 8 | (byte) Code.Rem_Un << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Push1 << 24); + + public static readonly OpCode And = new OpCode ( + 0xff << 0 | 0x5f << 8 | (byte) Code.And << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Push1 << 24); + + public static readonly OpCode Or = new OpCode ( + 0xff << 0 | 0x60 << 8 | (byte) Code.Or << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Push1 << 24); + + public static readonly OpCode Xor = new OpCode ( + 0xff << 0 | 0x61 << 8 | (byte) Code.Xor << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Push1 << 24); + + public static readonly OpCode Shl = new OpCode ( + 0xff << 0 | 0x62 << 8 | (byte) Code.Shl << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Push1 << 24); + + public static readonly OpCode Shr = new OpCode ( + 0xff << 0 | 0x63 << 8 | (byte) Code.Shr << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Push1 << 24); + + public static readonly OpCode Shr_Un = new OpCode ( + 0xff << 0 | 0x64 << 8 | (byte) Code.Shr_Un << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Push1 << 24); + + public static readonly OpCode Neg = new OpCode ( + 0xff << 0 | 0x65 << 8 | (byte) Code.Neg << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Push1 << 24); + + public static readonly OpCode Not = new OpCode ( + 0xff << 0 | 0x66 << 8 | (byte) Code.Not << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Push1 << 24); + + public static readonly OpCode Conv_I1 = new OpCode ( + 0xff << 0 | 0x67 << 8 | (byte) Code.Conv_I1 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_I2 = new OpCode ( + 0xff << 0 | 0x68 << 8 | (byte) Code.Conv_I2 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_I4 = new OpCode ( + 0xff << 0 | 0x69 << 8 | (byte) Code.Conv_I4 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_I8 = new OpCode ( + 0xff << 0 | 0x6a << 8 | (byte) Code.Conv_I8 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Pushi8 << 24); + + public static readonly OpCode Conv_R4 = new OpCode ( + 0xff << 0 | 0x6b << 8 | (byte) Code.Conv_R4 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Pushr4 << 24); + + public static readonly OpCode Conv_R8 = new OpCode ( + 0xff << 0 | 0x6c << 8 | (byte) Code.Conv_R8 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Pushr8 << 24); + + public static readonly OpCode Conv_U4 = new OpCode ( + 0xff << 0 | 0x6d << 8 | (byte) Code.Conv_U4 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_U8 = new OpCode ( + 0xff << 0 | 0x6e << 8 | (byte) Code.Conv_U8 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Pushi8 << 24); + + public static readonly OpCode Callvirt = new OpCode ( + 0xff << 0 | 0x6f << 8 | (byte) Code.Callvirt << 16 | (byte) FlowControl.Call << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineMethod << 8 | (byte) StackBehaviour.Varpop << 16 | (byte) StackBehaviour.Varpush << 24); + + public static readonly OpCode Cpobj = new OpCode ( + 0xff << 0 | 0x70 << 8 | (byte) Code.Cpobj << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineType << 8 | (byte) StackBehaviour.Popi_popi << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Ldobj = new OpCode ( + 0xff << 0 | 0x71 << 8 | (byte) Code.Ldobj << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineType << 8 | (byte) StackBehaviour.Popi << 16 | (byte) StackBehaviour.Push1 << 24); + + public static readonly OpCode Ldstr = new OpCode ( + 0xff << 0 | 0x72 << 8 | (byte) Code.Ldstr << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineString << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Pushref << 24); + + public static readonly OpCode Newobj = new OpCode ( + 0xff << 0 | 0x73 << 8 | (byte) Code.Newobj << 16 | (byte) FlowControl.Call << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineMethod << 8 | (byte) StackBehaviour.Varpop << 16 | (byte) StackBehaviour.Pushref << 24); + + public static readonly OpCode Castclass = new OpCode ( + 0xff << 0 | 0x74 << 8 | (byte) Code.Castclass << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineType << 8 | (byte) StackBehaviour.Popref << 16 | (byte) StackBehaviour.Pushref << 24); + + public static readonly OpCode Isinst = new OpCode ( + 0xff << 0 | 0x75 << 8 | (byte) Code.Isinst << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineType << 8 | (byte) StackBehaviour.Popref << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_R_Un = new OpCode ( + 0xff << 0 | 0x76 << 8 | (byte) Code.Conv_R_Un << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Pushr8 << 24); + + public static readonly OpCode Unbox = new OpCode ( + 0xff << 0 | 0x79 << 8 | (byte) Code.Unbox << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineType << 8 | (byte) StackBehaviour.Popref << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Throw = new OpCode ( + 0xff << 0 | 0x7a << 8 | (byte) Code.Throw << 16 | (byte) FlowControl.Throw << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popref << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Ldfld = new OpCode ( + 0xff << 0 | 0x7b << 8 | (byte) Code.Ldfld << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineField << 8 | (byte) StackBehaviour.Popref << 16 | (byte) StackBehaviour.Push1 << 24); + + public static readonly OpCode Ldflda = new OpCode ( + 0xff << 0 | 0x7c << 8 | (byte) Code.Ldflda << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineField << 8 | (byte) StackBehaviour.Popref << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Stfld = new OpCode ( + 0xff << 0 | 0x7d << 8 | (byte) Code.Stfld << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineField << 8 | (byte) StackBehaviour.Popref_pop1 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Ldsfld = new OpCode ( + 0xff << 0 | 0x7e << 8 | (byte) Code.Ldsfld << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineField << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Push1 << 24); + + public static readonly OpCode Ldsflda = new OpCode ( + 0xff << 0 | 0x7f << 8 | (byte) Code.Ldsflda << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineField << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Stsfld = new OpCode ( + 0xff << 0 | 0x80 << 8 | (byte) Code.Stsfld << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineField << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Stobj = new OpCode ( + 0xff << 0 | 0x81 << 8 | (byte) Code.Stobj << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineType << 8 | (byte) StackBehaviour.Popi_pop1 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Conv_Ovf_I1_Un = new OpCode ( + 0xff << 0 | 0x82 << 8 | (byte) Code.Conv_Ovf_I1_Un << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_Ovf_I2_Un = new OpCode ( + 0xff << 0 | 0x83 << 8 | (byte) Code.Conv_Ovf_I2_Un << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_Ovf_I4_Un = new OpCode ( + 0xff << 0 | 0x84 << 8 | (byte) Code.Conv_Ovf_I4_Un << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_Ovf_I8_Un = new OpCode ( + 0xff << 0 | 0x85 << 8 | (byte) Code.Conv_Ovf_I8_Un << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Pushi8 << 24); + + public static readonly OpCode Conv_Ovf_U1_Un = new OpCode ( + 0xff << 0 | 0x86 << 8 | (byte) Code.Conv_Ovf_U1_Un << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_Ovf_U2_Un = new OpCode ( + 0xff << 0 | 0x87 << 8 | (byte) Code.Conv_Ovf_U2_Un << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_Ovf_U4_Un = new OpCode ( + 0xff << 0 | 0x88 << 8 | (byte) Code.Conv_Ovf_U4_Un << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_Ovf_U8_Un = new OpCode ( + 0xff << 0 | 0x89 << 8 | (byte) Code.Conv_Ovf_U8_Un << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Pushi8 << 24); + + public static readonly OpCode Conv_Ovf_I_Un = new OpCode ( + 0xff << 0 | 0x8a << 8 | (byte) Code.Conv_Ovf_I_Un << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_Ovf_U_Un = new OpCode ( + 0xff << 0 | 0x8b << 8 | (byte) Code.Conv_Ovf_U_Un << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Box = new OpCode ( + 0xff << 0 | 0x8c << 8 | (byte) Code.Box << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineType << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Pushref << 24); + + public static readonly OpCode Newarr = new OpCode ( + 0xff << 0 | 0x8d << 8 | (byte) Code.Newarr << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineType << 8 | (byte) StackBehaviour.Popi << 16 | (byte) StackBehaviour.Pushref << 24); + + public static readonly OpCode Ldlen = new OpCode ( + 0xff << 0 | 0x8e << 8 | (byte) Code.Ldlen << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popref << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldelema = new OpCode ( + 0xff << 0 | 0x8f << 8 | (byte) Code.Ldelema << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineType << 8 | (byte) StackBehaviour.Popref_popi << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldelem_I1 = new OpCode ( + 0xff << 0 | 0x90 << 8 | (byte) Code.Ldelem_I1 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popref_popi << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldelem_U1 = new OpCode ( + 0xff << 0 | 0x91 << 8 | (byte) Code.Ldelem_U1 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popref_popi << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldelem_I2 = new OpCode ( + 0xff << 0 | 0x92 << 8 | (byte) Code.Ldelem_I2 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popref_popi << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldelem_U2 = new OpCode ( + 0xff << 0 | 0x93 << 8 | (byte) Code.Ldelem_U2 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popref_popi << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldelem_I4 = new OpCode ( + 0xff << 0 | 0x94 << 8 | (byte) Code.Ldelem_I4 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popref_popi << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldelem_U4 = new OpCode ( + 0xff << 0 | 0x95 << 8 | (byte) Code.Ldelem_U4 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popref_popi << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldelem_I8 = new OpCode ( + 0xff << 0 | 0x96 << 8 | (byte) Code.Ldelem_I8 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popref_popi << 16 | (byte) StackBehaviour.Pushi8 << 24); + + public static readonly OpCode Ldelem_I = new OpCode ( + 0xff << 0 | 0x97 << 8 | (byte) Code.Ldelem_I << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popref_popi << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldelem_R4 = new OpCode ( + 0xff << 0 | 0x98 << 8 | (byte) Code.Ldelem_R4 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popref_popi << 16 | (byte) StackBehaviour.Pushr4 << 24); + + public static readonly OpCode Ldelem_R8 = new OpCode ( + 0xff << 0 | 0x99 << 8 | (byte) Code.Ldelem_R8 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popref_popi << 16 | (byte) StackBehaviour.Pushr8 << 24); + + public static readonly OpCode Ldelem_Ref = new OpCode ( + 0xff << 0 | 0x9a << 8 | (byte) Code.Ldelem_Ref << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popref_popi << 16 | (byte) StackBehaviour.Pushref << 24); + + public static readonly OpCode Stelem_I = new OpCode ( + 0xff << 0 | 0x9b << 8 | (byte) Code.Stelem_I << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popref_popi_popi << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Stelem_I1 = new OpCode ( + 0xff << 0 | 0x9c << 8 | (byte) Code.Stelem_I1 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popref_popi_popi << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Stelem_I2 = new OpCode ( + 0xff << 0 | 0x9d << 8 | (byte) Code.Stelem_I2 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popref_popi_popi << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Stelem_I4 = new OpCode ( + 0xff << 0 | 0x9e << 8 | (byte) Code.Stelem_I4 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popref_popi_popi << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Stelem_I8 = new OpCode ( + 0xff << 0 | 0x9f << 8 | (byte) Code.Stelem_I8 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popref_popi_popi8 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Stelem_R4 = new OpCode ( + 0xff << 0 | 0xa0 << 8 | (byte) Code.Stelem_R4 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popref_popi_popr4 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Stelem_R8 = new OpCode ( + 0xff << 0 | 0xa1 << 8 | (byte) Code.Stelem_R8 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popref_popi_popr8 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Stelem_Ref = new OpCode ( + 0xff << 0 | 0xa2 << 8 | (byte) Code.Stelem_Ref << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popref_popi_popref << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Ldelem_Any = new OpCode ( + 0xff << 0 | 0xa3 << 8 | (byte) Code.Ldelem_Any << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineType << 8 | (byte) StackBehaviour.Popref_popi << 16 | (byte) StackBehaviour.Push1 << 24); + + public static readonly OpCode Stelem_Any = new OpCode ( + 0xff << 0 | 0xa4 << 8 | (byte) Code.Stelem_Any << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineType << 8 | (byte) StackBehaviour.Popref_popi_popref << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Unbox_Any = new OpCode ( + 0xff << 0 | 0xa5 << 8 | (byte) Code.Unbox_Any << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineType << 8 | (byte) StackBehaviour.Popref << 16 | (byte) StackBehaviour.Push1 << 24); + + public static readonly OpCode Conv_Ovf_I1 = new OpCode ( + 0xff << 0 | 0xb3 << 8 | (byte) Code.Conv_Ovf_I1 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_Ovf_U1 = new OpCode ( + 0xff << 0 | 0xb4 << 8 | (byte) Code.Conv_Ovf_U1 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_Ovf_I2 = new OpCode ( + 0xff << 0 | 0xb5 << 8 | (byte) Code.Conv_Ovf_I2 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_Ovf_U2 = new OpCode ( + 0xff << 0 | 0xb6 << 8 | (byte) Code.Conv_Ovf_U2 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_Ovf_I4 = new OpCode ( + 0xff << 0 | 0xb7 << 8 | (byte) Code.Conv_Ovf_I4 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_Ovf_U4 = new OpCode ( + 0xff << 0 | 0xb8 << 8 | (byte) Code.Conv_Ovf_U4 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_Ovf_I8 = new OpCode ( + 0xff << 0 | 0xb9 << 8 | (byte) Code.Conv_Ovf_I8 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Pushi8 << 24); + + public static readonly OpCode Conv_Ovf_U8 = new OpCode ( + 0xff << 0 | 0xba << 8 | (byte) Code.Conv_Ovf_U8 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Pushi8 << 24); + + public static readonly OpCode Refanyval = new OpCode ( + 0xff << 0 | 0xc2 << 8 | (byte) Code.Refanyval << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineType << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Ckfinite = new OpCode ( + 0xff << 0 | 0xc3 << 8 | (byte) Code.Ckfinite << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Pushr8 << 24); + + public static readonly OpCode Mkrefany = new OpCode ( + 0xff << 0 | 0xc6 << 8 | (byte) Code.Mkrefany << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineType << 8 | (byte) StackBehaviour.Popi << 16 | (byte) StackBehaviour.Push1 << 24); + + public static readonly OpCode Ldtoken = new OpCode ( + 0xff << 0 | 0xd0 << 8 | (byte) Code.Ldtoken << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineTok << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_U2 = new OpCode ( + 0xff << 0 | 0xd1 << 8 | (byte) Code.Conv_U2 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_U1 = new OpCode ( + 0xff << 0 | 0xd2 << 8 | (byte) Code.Conv_U1 << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_I = new OpCode ( + 0xff << 0 | 0xd3 << 8 | (byte) Code.Conv_I << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_Ovf_I = new OpCode ( + 0xff << 0 | 0xd4 << 8 | (byte) Code.Conv_Ovf_I << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Conv_Ovf_U = new OpCode ( + 0xff << 0 | 0xd5 << 8 | (byte) Code.Conv_Ovf_U << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Add_Ovf = new OpCode ( + 0xff << 0 | 0xd6 << 8 | (byte) Code.Add_Ovf << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Push1 << 24); + + public static readonly OpCode Add_Ovf_Un = new OpCode ( + 0xff << 0 | 0xd7 << 8 | (byte) Code.Add_Ovf_Un << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Push1 << 24); + + public static readonly OpCode Mul_Ovf = new OpCode ( + 0xff << 0 | 0xd8 << 8 | (byte) Code.Mul_Ovf << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Push1 << 24); + + public static readonly OpCode Mul_Ovf_Un = new OpCode ( + 0xff << 0 | 0xd9 << 8 | (byte) Code.Mul_Ovf_Un << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Push1 << 24); + + public static readonly OpCode Sub_Ovf = new OpCode ( + 0xff << 0 | 0xda << 8 | (byte) Code.Sub_Ovf << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Push1 << 24); + + public static readonly OpCode Sub_Ovf_Un = new OpCode ( + 0xff << 0 | 0xdb << 8 | (byte) Code.Sub_Ovf_Un << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Push1 << 24); + + public static readonly OpCode Endfinally = new OpCode ( + 0xff << 0 | 0xdc << 8 | (byte) Code.Endfinally << 16 | (byte) FlowControl.Return << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Leave = new OpCode ( + 0xff << 0 | 0xdd << 8 | (byte) Code.Leave << 16 | (byte) FlowControl.Branch << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineBrTarget << 8 | (byte) StackBehaviour.PopAll << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Leave_S = new OpCode ( + 0xff << 0 | 0xde << 8 | (byte) Code.Leave_S << 16 | (byte) FlowControl.Branch << 24, + (byte) OpCodeType.Macro << 0 | (byte) OperandType.ShortInlineBrTarget << 8 | (byte) StackBehaviour.PopAll << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Stind_I = new OpCode ( + 0xff << 0 | 0xdf << 8 | (byte) Code.Stind_I << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popi_popi << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Conv_U = new OpCode ( + 0xff << 0 | 0xe0 << 8 | (byte) Code.Conv_U << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Arglist = new OpCode ( + 0xfe << 0 | 0x00 << 8 | (byte) Code.Arglist << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Ceq = new OpCode ( + 0xfe << 0 | 0x01 << 8 | (byte) Code.Ceq << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Cgt = new OpCode ( + 0xfe << 0 | 0x02 << 8 | (byte) Code.Cgt << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Cgt_Un = new OpCode ( + 0xfe << 0 | 0x03 << 8 | (byte) Code.Cgt_Un << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Clt = new OpCode ( + 0xfe << 0 | 0x04 << 8 | (byte) Code.Clt << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Clt_Un = new OpCode ( + 0xfe << 0 | 0x05 << 8 | (byte) Code.Clt_Un << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1_pop1 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldftn = new OpCode ( + 0xfe << 0 | 0x06 << 8 | (byte) Code.Ldftn << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineMethod << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldvirtftn = new OpCode ( + 0xfe << 0 | 0x07 << 8 | (byte) Code.Ldvirtftn << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineMethod << 8 | (byte) StackBehaviour.Popref << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Ldarg = new OpCode ( + 0xfe << 0 | 0x09 << 8 | (byte) Code.Ldarg << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineArg << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Push1 << 24); + + public static readonly OpCode Ldarga = new OpCode ( + 0xfe << 0 | 0x0a << 8 | (byte) Code.Ldarga << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineArg << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Starg = new OpCode ( + 0xfe << 0 | 0x0b << 8 | (byte) Code.Starg << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineArg << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Ldloc = new OpCode ( + 0xfe << 0 | 0x0c << 8 | (byte) Code.Ldloc << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineVar << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Push1 << 24); + + public static readonly OpCode Ldloca = new OpCode ( + 0xfe << 0 | 0x0d << 8 | (byte) Code.Ldloca << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineVar << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Stloc = new OpCode ( + 0xfe << 0 | 0x0e << 8 | (byte) Code.Stloc << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineVar << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Localloc = new OpCode ( + 0xfe << 0 | 0x0f << 8 | (byte) Code.Localloc << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popi << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Endfilter = new OpCode ( + 0xfe << 0 | 0x11 << 8 | (byte) Code.Endfilter << 16 | (byte) FlowControl.Return << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popi << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Unaligned = new OpCode ( + 0xfe << 0 | 0x12 << 8 | (byte) Code.Unaligned << 16 | (byte) FlowControl.Meta << 24, + (byte) OpCodeType.Prefix << 0 | (byte) OperandType.ShortInlineI << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Volatile = new OpCode ( + 0xfe << 0 | 0x13 << 8 | (byte) Code.Volatile << 16 | (byte) FlowControl.Meta << 24, + (byte) OpCodeType.Prefix << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Tail = new OpCode ( + 0xfe << 0 | 0x14 << 8 | (byte) Code.Tail << 16 | (byte) FlowControl.Meta << 24, + (byte) OpCodeType.Prefix << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Initobj = new OpCode ( + 0xfe << 0 | 0x15 << 8 | (byte) Code.Initobj << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineType << 8 | (byte) StackBehaviour.Popi << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Constrained = new OpCode ( + 0xfe << 0 | 0x16 << 8 | (byte) Code.Constrained << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Prefix << 0 | (byte) OperandType.InlineType << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Cpblk = new OpCode ( + 0xfe << 0 | 0x17 << 8 | (byte) Code.Cpblk << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popi_popi_popi << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Initblk = new OpCode ( + 0xfe << 0 | 0x18 << 8 | (byte) Code.Initblk << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Popi_popi_popi << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode No = new OpCode ( + 0xfe << 0 | 0x19 << 8 | (byte) Code.No << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Prefix << 0 | (byte) OperandType.ShortInlineI << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Rethrow = new OpCode ( + 0xfe << 0 | 0x1a << 8 | (byte) Code.Rethrow << 16 | (byte) FlowControl.Throw << 24, + (byte) OpCodeType.Objmodel << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Push0 << 24); + + public static readonly OpCode Sizeof = new OpCode ( + 0xfe << 0 | 0x1c << 8 | (byte) Code.Sizeof << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineType << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Refanytype = new OpCode ( + 0xfe << 0 | 0x1d << 8 | (byte) Code.Refanytype << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop1 << 16 | (byte) StackBehaviour.Pushi << 24); + + public static readonly OpCode Readonly = new OpCode ( + 0xfe << 0 | 0x1e << 8 | (byte) Code.Readonly << 16 | (byte) FlowControl.Next << 24, + (byte) OpCodeType.Prefix << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Push0 << 24); + } +} diff --git a/Mono.Cecil.Cil/SequencePoint.cs b/Mono.Cecil.Cil/SequencePoint.cs new file mode 100644 index 000000000..189b5f52b --- /dev/null +++ b/Mono.Cecil.Cil/SequencePoint.cs @@ -0,0 +1,70 @@ +// +// SequencePoint.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace Mono.Cecil.Cil { + + public sealed class SequencePoint { + + Document document; + + int start_line; + int start_column; + int end_line; + int end_column; + + public int StartLine { + get { return start_line; } + set { start_line = value; } + } + + public int StartColumn { + get { return start_column; } + set { start_column = value; } + } + + public int EndLine { + get { return end_line; } + set { end_line = value; } + } + + public int EndColumn { + get { return end_column; } + set { end_column = value; } + } + + public Document Document { + get { return document; } + set { document = value; } + } + + public SequencePoint (Document document) + { + this.document = document; + } + } +} diff --git a/Mono.Cecil.Cil/Symbols.cs b/Mono.Cecil.Cil/Symbols.cs new file mode 100644 index 000000000..ba2e694fc --- /dev/null +++ b/Mono.Cecil.Cil/Symbols.cs @@ -0,0 +1,272 @@ +// +// Symbols.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.IO; +using System.Runtime.InteropServices; +using SR = System.Reflection; + +using Mono.Collections.Generic; + +namespace Mono.Cecil.Cil { + + [StructLayout (LayoutKind.Sequential)] + public struct ImageDebugDirectory { + public int Characteristics; + public int TimeDateStamp; + public short MajorVersion; + public short MinorVersion; + public int Type; + public int SizeOfData; + public int AddressOfRawData; + public int PointerToRawData; + } + + public sealed class Scope : IVariableDefinitionProvider { + + Instruction start; + Instruction end; + + Collection scopes; + Collection variables; + + public Instruction Start { + get { return start; } + set { start = value; } + } + + public Instruction End { + get { return end; } + set { end = value; } + } + + public bool HasScopes { + get { return !scopes.IsNullOrEmpty (); } + } + + public Collection Scopes { + get { + if (scopes == null) + scopes = new Collection (); + + return scopes; + } + } + + public bool HasVariables { + get { return !variables.IsNullOrEmpty (); } + } + + public Collection Variables { + get { + if (variables == null) + variables = new Collection (); + + return variables; + } + } + } + + public struct InstructionSymbol { + + public readonly int Offset; + public readonly SequencePoint SequencePoint; + + public InstructionSymbol (int offset, SequencePoint sequencePoint) + { + this.Offset = offset; + this.SequencePoint = sequencePoint; + } + } + + public sealed class MethodSymbols { + + internal int code_size; + internal string method_name; + internal MetadataToken method_token; + internal MetadataToken local_var_token; + internal Collection variables; + internal Collection instructions; + + public bool HasVariables { + get { return !variables.IsNullOrEmpty (); } + } + + public Collection Variables { + get { + if (variables == null) + variables = new Collection (); + + return variables; + } + } + + public Collection Instructions { + get { + if (instructions == null) + instructions = new Collection (); + + return instructions; + } + } + + public int CodeSize { + get { return code_size; } + } + + public string MethodName { + get { return method_name; } + } + + public MetadataToken MethodToken { + get { return method_token; } + } + + public MetadataToken LocalVarToken { + get { return local_var_token; } + } + + public MethodSymbols (string methodName) + { + this.method_name = methodName; + } + } + + public delegate Instruction InstructionMapper (int offset); + + public interface ISymbolReader : IDisposable { + + bool ProcessDebugHeader (ImageDebugDirectory directory, byte [] header); + void Read (MethodBody body, InstructionMapper mapper); + void Read (MethodSymbols symbols); + } + + public interface ISymbolReaderProvider { + + ISymbolReader GetSymbolReader (ModuleDefinition module, string fileName); + ISymbolReader GetSymbolReader (ModuleDefinition module, Stream symbolStream); + } + + static class SymbolProvider { + + static readonly string symbol_kind = Type.GetType ("Mono.Runtime") != null ? "Mdb" : "Pdb"; + + static SR.AssemblyName GetPlatformSymbolAssemblyName () + { + var cecil_name = typeof (SymbolProvider).Assembly.GetName (); + + var name = new SR.AssemblyName { + Name = "Mono.Cecil." + symbol_kind, + Version = cecil_name.Version, + }; + + name.SetPublicKeyToken (cecil_name.GetPublicKeyToken ()); + + return name; + } + + static Type GetPlatformType (string fullname) + { + var type = Type.GetType (fullname); + if (type != null) + return type; + + var assembly_name = GetPlatformSymbolAssemblyName (); + + type = Type.GetType (fullname + ", " + assembly_name.FullName); + if (type != null) + return type; + + try { + var assembly = SR.Assembly.Load (assembly_name); + if (assembly != null) + return assembly.GetType (fullname); + } catch (FileNotFoundException) { +#if !CF + } catch (FileLoadException) { +#endif + } + + return null; + } + + static ISymbolReaderProvider reader_provider; + + public static ISymbolReaderProvider GetPlatformReaderProvider () + { + if (reader_provider != null) + return reader_provider; + + var type = GetPlatformType (GetProviderTypeName ("ReaderProvider")); + if (type == null) + return null; + + return reader_provider = (ISymbolReaderProvider) Activator.CreateInstance (type); + } + + static string GetProviderTypeName (string name) + { + return "Mono.Cecil." + symbol_kind + "." + symbol_kind + name; + } + +#if !READ_ONLY + + static ISymbolWriterProvider writer_provider; + + public static ISymbolWriterProvider GetPlatformWriterProvider () + { + if (writer_provider != null) + return writer_provider; + + var type = GetPlatformType (GetProviderTypeName ("WriterProvider")); + if (type == null) + return null; + + return writer_provider = (ISymbolWriterProvider) Activator.CreateInstance (type); + } + +#endif + } + +#if !READ_ONLY + + public interface ISymbolWriter : IDisposable { + + bool GetDebugHeader (out ImageDebugDirectory directory, out byte [] header); + void Write (MethodBody body); + void Write (MethodSymbols symbols); + } + + public interface ISymbolWriterProvider { + + ISymbolWriter GetSymbolWriter (ModuleDefinition module, string fileName); + ISymbolWriter GetSymbolWriter (ModuleDefinition module, Stream symbolStream); + } + +#endif +} diff --git a/Mono.Cecil.Cil/VariableDefinition.cs b/Mono.Cecil.Cil/VariableDefinition.cs new file mode 100644 index 000000000..690543e97 --- /dev/null +++ b/Mono.Cecil.Cil/VariableDefinition.cs @@ -0,0 +1,52 @@ +// +// VariableDefinition.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace Mono.Cecil.Cil { + + public sealed class VariableDefinition : VariableReference { + + public bool IsPinned { + get { return variable_type.IsPinned; } + } + + public VariableDefinition (TypeReference variableType) + : base (variableType) + { + } + + public VariableDefinition (string name, TypeReference variableType) + : base (name, variableType) + { + } + + public override VariableDefinition Resolve () + { + return this; + } + } +} diff --git a/Mono.Cecil.Cil/VariableReference.cs b/Mono.Cecil.Cil/VariableReference.cs new file mode 100644 index 000000000..545384550 --- /dev/null +++ b/Mono.Cecil.Cil/VariableReference.cs @@ -0,0 +1,75 @@ +// +// VariableReference.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace Mono.Cecil.Cil { + + public abstract class VariableReference { + + string name; + internal int index = -1; + protected TypeReference variable_type; + + public string Name { + get { return name; } + set { name = value; } + } + + public TypeReference VariableType { + get { return variable_type; } + set { variable_type = value; } + } + + public int Index { + get { return index; } + } + + internal VariableReference (TypeReference variable_type) + : this (string.Empty, variable_type) + { + } + + internal VariableReference (string name, TypeReference variable_type) + { + this.name = name; + this.variable_type = variable_type; + } + + public abstract VariableDefinition Resolve (); + + public override string ToString () + { + if (!string.IsNullOrEmpty (name)) + return name; + + if (index >= 0) + return "V_" + index; + + return string.Empty; + } + } +} diff --git a/Mono.Cecil.Metadata/BlobHeap.cs b/Mono.Cecil.Metadata/BlobHeap.cs new file mode 100644 index 000000000..81c775e01 --- /dev/null +++ b/Mono.Cecil.Metadata/BlobHeap.cs @@ -0,0 +1,59 @@ +// +// BlobHeap.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +using Mono.Cecil.PE; + +namespace Mono.Cecil.Metadata { + + sealed class BlobHeap : Heap { + + public BlobHeap (Section section, uint start, uint size) + : base (section, start, size) + { + } + + public byte [] Read (uint index) + { + if (index == 0 || index > Size - 1) + return Empty.Array; + + var data = Section.Data; + + int position = (int) (index + Offset); + int length = (int) data.ReadCompressedUInt32 (ref position); + + var buffer = new byte [length]; + + Buffer.BlockCopy (data, position, buffer, 0, length); + + return buffer; + } + } +} diff --git a/Mono.Cecil.Metadata/Buffers.cs b/Mono.Cecil.Metadata/Buffers.cs new file mode 100644 index 000000000..e8759d742 --- /dev/null +++ b/Mono.Cecil.Metadata/Buffers.cs @@ -0,0 +1,373 @@ +// +// TableHeapBuffer.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Generic; +using System.Text; + +using Mono.Cecil.PE; + +using RVA = System.UInt32; + +#if !READ_ONLY + +namespace Mono.Cecil.Metadata { + + sealed class TableHeapBuffer : HeapBuffer { + + readonly ModuleDefinition module; + readonly MetadataBuilder metadata; + + internal MetadataTable [] tables = new MetadataTable [45]; + + bool large_string; + bool large_blob; + readonly int [] coded_index_sizes = new int [13]; + readonly Func counter; + + public override bool IsEmpty { + get { return false; } + } + + public TableHeapBuffer (ModuleDefinition module, MetadataBuilder metadata) + : base (24) + { + this.module = module; + this.metadata = metadata; + this.counter = GetTableLength; + } + + int GetTableLength (Table table) + { + var md_table = tables [(int) table]; + return md_table != null ? md_table.Length : 0; + } + + public TTable GetTable (Table table) where TTable : MetadataTable, new () + { + var md_table = (TTable) tables [(int) table]; + if (md_table != null) + return md_table; + + md_table = new TTable (); + tables [(int) table] = md_table; + return md_table; + } + + public void WriteBySize (uint value, int size) + { + if (size == 4) + WriteUInt32 (value); + else + WriteUInt16 ((ushort) value); + } + + public void WriteBySize (uint value, bool large) + { + if (large) + WriteUInt32 (value); + else + WriteUInt16 ((ushort) value); + } + + public void WriteString (uint @string) + { + WriteBySize (@string, large_string); + } + + public void WriteBlob (uint blob) + { + WriteBySize (blob, large_blob); + } + + public void WriteRID (uint rid, Table table) + { + var md_table = tables [(int) table]; + WriteBySize (rid, md_table == null ? false : md_table.IsLarge); + } + + int GetCodedIndexSize (CodedIndex coded_index) + { + var index = (int) coded_index; + var size = coded_index_sizes [index]; + if (size != 0) + return size; + + return coded_index_sizes [index] = coded_index.GetSize (counter); + } + + public void WriteCodedRID (uint rid, CodedIndex coded_index) + { + WriteBySize (rid, GetCodedIndexSize (coded_index)); + } + + public void WriteTableHeap () + { + WriteUInt32 (0); // Reserved + WriteByte (GetTableHeapVersion ()); // MajorVersion + WriteByte (0); // MinorVersion + WriteByte (GetHeapSizes ()); // HeapSizes + WriteByte (10); // Reserved2 + WriteUInt64 (GetValid ()); // Valid + WriteUInt64 (0x0016003301fa00); // Sorted + + WriteRowCount (); + WriteTables (); + } + + void WriteRowCount () + { + for (int i = 0; i < tables.Length; i++) { + var table = tables [i]; + if (table == null || table.Length == 0) + continue; + + WriteUInt32 ((uint) table.Length); + } + } + + void WriteTables () + { + for (int i = 0; i < tables.Length; i++) { + var table = tables [i]; + if (table == null || table.Length == 0) + continue; + + table.Write (this); + } + } + + ulong GetValid () + { + ulong valid = 0; + + for (int i = 0; i < tables.Length; i++) { + var table = tables [i]; + if (table == null || table.Length == 0) + continue; + + table.Sort (); + valid |= (1UL << i); + } + + return valid; + } + + byte GetHeapSizes () + { + byte heap_sizes = 0; + + if (metadata.string_heap.IsLarge) { + large_string = true; + heap_sizes |= 0x01; + } + + if (metadata.blob_heap.IsLarge) { + large_blob = true; + heap_sizes |= 0x04; + } + + return heap_sizes; + } + + byte GetTableHeapVersion () + { + switch (module.Runtime) { + case TargetRuntime.Net_1_0: + case TargetRuntime.Net_1_1: + return 1; + default: + return 2; + } + } + + public void FixupData (RVA data_rva) + { + var table = GetTable (Table.FieldRVA); + if (table.length == 0) + return; + + var field_idx_size = GetTable (Table.Field).IsLarge ? 4 : 2; + var previous = this.position; + + base.position = table.position; + for (int i = 0; i < table.length; i++) { + var rva = ReadUInt32 (); + base.position -= 4; + WriteUInt32 (rva + data_rva); + base.position += field_idx_size; + } + + base.position = previous; + } + } + + sealed class ResourceBuffer : ByteBuffer { + + public ResourceBuffer () + : base (0) + { + } + + public uint AddResource (byte [] resource) + { + var offset = (uint) this.position; + WriteInt32 (resource.Length); + WriteBytes (resource); + return offset; + } + } + + sealed class DataBuffer : ByteBuffer { + + public DataBuffer () + : base (0) + { + } + + public RVA AddData (byte [] data) + { + var rva = (RVA) position; + WriteBytes (data); + return rva; + } + } + + abstract class HeapBuffer : ByteBuffer { + + public bool IsLarge { + get { return base.length > 65536; } + } + + public abstract bool IsEmpty { get; } + + protected HeapBuffer (int length) + : base (length) + { + } + } + + class StringHeapBuffer : HeapBuffer { + + readonly Dictionary strings = new Dictionary (); + + public sealed override bool IsEmpty { + get { return length <= 1; } + } + + public StringHeapBuffer () + : base (1) + { + WriteByte (0); + } + + public uint GetStringIndex (string @string) + { + uint index; + if (strings.TryGetValue (@string, out index)) + return index; + + index = (uint) base.position; + WriteString (@string); + strings.Add (@string, index); + return index; + } + + protected virtual void WriteString (string @string) + { + WriteBytes (Encoding.UTF8.GetBytes (@string)); + WriteByte (0); + } + } + + sealed class BlobHeapBuffer : HeapBuffer { + + readonly Dictionary blobs = new Dictionary (new ByteBufferEqualityComparer ()); + + public override bool IsEmpty { + get { return length <= 1; } + } + + public BlobHeapBuffer () + : base (1) + { + WriteByte (0); + } + + public uint GetBlobIndex (ByteBuffer blob) + { + uint index; + if (blobs.TryGetValue (blob, out index)) + return index; + + index = (uint) base.position; + WriteBlob (blob); + blobs.Add (blob, index); + return index; + } + + void WriteBlob (ByteBuffer blob) + { + WriteCompressedUInt32 ((uint) blob.length); + WriteBytes (blob); + } + } + + sealed class UserStringHeapBuffer : StringHeapBuffer { + + protected override void WriteString (string @string) + { + WriteCompressedUInt32 ((uint) @string.Length * 2 + 1); + + byte special = 0; + + for (int i = 0; i < @string.Length; i++) { + var @char = @string [i]; + WriteUInt16 (@char); + + if (special == 1) + continue; + + if (@char < 0x20 || @char > 0x7e) { + if (@char > 0x7e + || (@char >= 0x01 && @char <= 0x08) + || (@char >= 0x0e && @char <= 0x1f) + || @char == 0x27 + || @char == 0x2d) { + + special = 1; + } + } + } + + WriteByte (special); + } + } +} + +#endif diff --git a/Mono.Cecil.Metadata/CodedIndex.cs b/Mono.Cecil.Metadata/CodedIndex.cs new file mode 100644 index 000000000..62677263d --- /dev/null +++ b/Mono.Cecil.Metadata/CodedIndex.cs @@ -0,0 +1,46 @@ +// +// CodedIndex.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace Mono.Cecil.Metadata { + + enum CodedIndex { + TypeDefOrRef, + HasConstant, + HasCustomAttribute, + HasFieldMarshal, + HasDeclSecurity, + MemberRefParent, + HasSemantics, + MethodDefOrRef, + MemberForwarded, + Implementation, + CustomAttributeType, + ResolutionScope, + TypeOrMethodDef + } +} diff --git a/Mono.Cecil.Metadata/ElementType.cs b/Mono.Cecil.Metadata/ElementType.cs new file mode 100644 index 000000000..1ede042b5 --- /dev/null +++ b/Mono.Cecil.Metadata/ElementType.cs @@ -0,0 +1,73 @@ +// +// ElementType.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace Mono.Cecil.Metadata { + + enum ElementType : byte { + None = 0x00, + Void = 0x01, + Boolean = 0x02, + Char = 0x03, + I1 = 0x04, + U1 = 0x05, + I2 = 0x06, + U2 = 0x07, + I4 = 0x08, + U4 = 0x09, + I8 = 0x0a, + U8 = 0x0b, + R4 = 0x0c, + R8 = 0x0d, + String = 0x0e, + Ptr = 0x0f, // Followed by token + ByRef = 0x10, // Followed by token + ValueType = 0x11, // Followed by token + Class = 0x12, // Followed by token + Var = 0x13, // Followed by generic parameter number + Array = 0x14, // + GenericInst = 0x15, // ... */ + TypedByRef = 0x16, + I = 0x18, // System.IntPtr + U = 0x19, // System.UIntPtr + FnPtr = 0x1b, // Followed by full method signature + Object = 0x1c, // System.Object + SzArray = 0x1d, // Single-dim array with 0 lower bound + MVar = 0x1e, // Followed by generic parameter number + CModReqD = 0x1f, // Required modifier : followed by a TypeDef or TypeRef token + CModOpt = 0x20, // Optional modifier : followed by a TypeDef or TypeRef token + Internal = 0x21, // Implemented within the CLI + Modifier = 0x40, // Or'd with following element types + Sentinel = 0x41, // Sentinel for varargs method signature + Pinned = 0x45, // Denotes a local variable that points at a pinned object + + // special undocumented constants + Type = 0x50, + Boxed = 0x51, + Enum = 0x55 + } +} diff --git a/Mono.Cecil.Metadata/GuidHeap.cs b/Mono.Cecil.Metadata/GuidHeap.cs new file mode 100644 index 000000000..19acdab51 --- /dev/null +++ b/Mono.Cecil.Metadata/GuidHeap.cs @@ -0,0 +1,59 @@ +// +// GuidHeap.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +using Mono.Cecil.PE; + +namespace Mono.Cecil.Metadata { + + sealed class GuidHeap : Heap { + + public GuidHeap (Section section, uint start, uint size) + : base (section, start, size) + { + } + + public Guid Read (uint index) + { + if (index == 0) + return new Guid (); + + const int guid_size = 16; + + var buffer = new byte [guid_size]; + + index--; + + Buffer.BlockCopy (Section.Data, (int) (Offset + index), buffer, 0, guid_size); + + return new Guid (buffer); + + } + } +} diff --git a/Mono.Cecil.Metadata/Heap.cs b/Mono.Cecil.Metadata/Heap.cs new file mode 100644 index 000000000..e7ff72059 --- /dev/null +++ b/Mono.Cecil.Metadata/Heap.cs @@ -0,0 +1,48 @@ +// +// Heap.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using Mono.Cecil.PE; + +namespace Mono.Cecil.Metadata { + + abstract class Heap { + + public int IndexSize; + + public readonly Section Section; + public readonly uint Offset; + public readonly uint Size; + + protected Heap (Section section, uint offset, uint size) + { + this.Section = section; + this.Offset = offset; + this.Size = size; + } + } +} diff --git a/Mono.Cecil.Metadata/MetadataToken.cs b/Mono.Cecil.Metadata/MetadataToken.cs new file mode 100644 index 000000000..8c1338e94 --- /dev/null +++ b/Mono.Cecil.Metadata/MetadataToken.cs @@ -0,0 +1,105 @@ +// +// MetadataToken.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace Mono.Cecil { + + public struct MetadataToken { + + readonly uint token; + + public uint RID { + get { return token & 0x00ffffff; } + } + + public TokenType TokenType { + get { return (TokenType) (token & 0xff000000); } + } + + public static readonly MetadataToken Zero = new MetadataToken ((uint) 0); + + public MetadataToken (uint token) + { + this.token = token; + } + + public MetadataToken (TokenType type) + : this (type, 0) + { + } + + public MetadataToken (TokenType type, uint rid) + { + token = (uint) type | rid; + } + + public MetadataToken (TokenType type, int rid) + { + token = (uint) type | (uint) rid; + } + + public int ToInt32 () + { + return (int) token; + } + + public uint ToUInt32 () + { + return token; + } + + public override int GetHashCode () + { + return (int) token; + } + + public override bool Equals (object obj) + { + if (obj is MetadataToken) { + var other = (MetadataToken) obj; + return other.token == token; + } + + return false; + } + + public static bool operator == (MetadataToken one, MetadataToken other) + { + return one.token == other.token; + } + + public static bool operator != (MetadataToken one, MetadataToken other) + { + return one.token != other.token; + } + + public override string ToString () + { + return string.Format ("[{0}:0x{1}]", TokenType, RID.ToString ("x4")); + } + } +} diff --git a/Mono.Cecil.Metadata/Row.cs b/Mono.Cecil.Metadata/Row.cs new file mode 100644 index 000000000..ab491a6e2 --- /dev/null +++ b/Mono.Cecil.Metadata/Row.cs @@ -0,0 +1,170 @@ +// +// Row.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System.Collections.Generic; + +namespace Mono.Cecil.Metadata { + + struct Row { + internal T1 Col1; + internal T2 Col2; + + public Row (T1 col1, T2 col2) + { + Col1 = col1; + Col2 = col2; + } + } + + struct Row { + internal T1 Col1; + internal T2 Col2; + internal T3 Col3; + + public Row (T1 col1, T2 col2, T3 col3) + { + Col1 = col1; + Col2 = col2; + Col3 = col3; + } + } + + struct Row { + internal T1 Col1; + internal T2 Col2; + internal T3 Col3; + internal T4 Col4; + + public Row (T1 col1, T2 col2, T3 col3, T4 col4) + { + Col1 = col1; + Col2 = col2; + Col3 = col3; + Col4 = col4; + } + } + + struct Row { + internal T1 Col1; + internal T2 Col2; + internal T3 Col3; + internal T4 Col4; + internal T5 Col5; + + public Row (T1 col1, T2 col2, T3 col3, T4 col4, T5 col5) + { + Col1 = col1; + Col2 = col2; + Col3 = col3; + Col4 = col4; + Col5 = col5; + } + } + + struct Row { + internal T1 Col1; + internal T2 Col2; + internal T3 Col3; + internal T4 Col4; + internal T5 Col5; + internal T6 Col6; + + public Row (T1 col1, T2 col2, T3 col3, T4 col4, T5 col5, T6 col6) + { + Col1 = col1; + Col2 = col2; + Col3 = col3; + Col4 = col4; + Col5 = col5; + Col6 = col6; + } + } + + struct Row { + internal T1 Col1; + internal T2 Col2; + internal T3 Col3; + internal T4 Col4; + internal T5 Col5; + internal T6 Col6; + internal T7 Col7; + internal T8 Col8; + internal T9 Col9; + + public Row (T1 col1, T2 col2, T3 col3, T4 col4, T5 col5, T6 col6, T7 col7, T8 col8, T9 col9) + { + Col1 = col1; + Col2 = col2; + Col3 = col3; + Col4 = col4; + Col5 = col5; + Col6 = col6; + Col7 = col7; + Col8 = col8; + Col9 = col9; + } + } + + sealed class RowEqualityComparer : IEqualityComparer>, IEqualityComparer>, IEqualityComparer> { + + public bool Equals (Row x, Row y) + { + return x.Col1 == y.Col1 + && x.Col2 == y.Col2; + } + + public int GetHashCode (Row obj) + { + string x = obj.Col1, y = obj.Col2; + return (x != null ? x.GetHashCode () : 0) ^ (y != null ? y.GetHashCode () : 0); + } + + public bool Equals (Row x, Row y) + { + return x.Col1 == y.Col1 + && x.Col2 == y.Col2; + } + + public int GetHashCode (Row obj) + { + return (int) (obj.Col1 ^ obj.Col2); + } + + public bool Equals (Row x, Row y) + { + return x.Col1 == y.Col1 + && x.Col2 == y.Col2 + && x.Col3 == y.Col3; + } + + public int GetHashCode (Row obj) + { + return (int) (obj.Col1 ^ obj.Col2 ^ obj.Col3); + } + } +} diff --git a/Mono.Cecil.Metadata/StringHeap.cs b/Mono.Cecil.Metadata/StringHeap.cs new file mode 100644 index 000000000..85a289213 --- /dev/null +++ b/Mono.Cecil.Metadata/StringHeap.cs @@ -0,0 +1,81 @@ +// +// StringHeap.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Generic; +using System.Text; + +using Mono.Cecil.PE; + +namespace Mono.Cecil.Metadata { + + class StringHeap : Heap { + + readonly Dictionary strings = new Dictionary (); + + public StringHeap (Section section, uint start, uint size) + : base (section, start, size) + { + } + + public string Read (uint index) + { + if (index == 0) + return string.Empty; + + string @string; + if (strings.TryGetValue (index, out @string)) + return @string; + + if (index > Size - 1) + return string.Empty; + + @string = ReadStringAt (index); + if (@string.Length != 0) + strings.Add (index, @string); + + return @string; + } + + protected virtual string ReadStringAt (uint index) + { + int length = 0; + byte [] data = Section.Data; + int start = (int) (index + Offset); + + for (int i = start; ; i++) { + if (data [i] == 0) + break; + + length++; + } + + return Encoding.UTF8.GetString (data, start, length); + } + } +} diff --git a/Mono.Cecil.Metadata/TableHeap.cs b/Mono.Cecil.Metadata/TableHeap.cs new file mode 100644 index 000000000..cc441db25 --- /dev/null +++ b/Mono.Cecil.Metadata/TableHeap.cs @@ -0,0 +1,153 @@ +// +// TableHeap.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using Mono.Cecil.PE; + +namespace Mono.Cecil.Metadata { + + enum Table : byte { + Module = 0x00, + TypeRef = 0x01, + TypeDef = 0x02, + FieldPtr = 0x03, + Field = 0x04, + MethodPtr = 0x05, + Method = 0x06, + ParamPtr = 0x07, + Param = 0x08, + InterfaceImpl = 0x09, + MemberRef = 0x0a, + Constant = 0x0b, + CustomAttribute = 0x0c, + FieldMarshal = 0x0d, + DeclSecurity = 0x0e, + ClassLayout = 0x0f, + FieldLayout = 0x10, + StandAloneSig = 0x11, + EventMap = 0x12, + EventPtr = 0x13, + Event = 0x14, + PropertyMap = 0x15, + PropertyPtr = 0x16, + Property = 0x17, + MethodSemantics = 0x18, + MethodImpl = 0x19, + ModuleRef = 0x1a, + TypeSpec = 0x1b, + ImplMap = 0x1c, + FieldRVA = 0x1d, + Assembly = 0x20, + AssemblyProcessor = 0x21, + AssemblyOS = 0x22, + AssemblyRef = 0x23, + AssemblyRefProcessor = 0x24, + AssemblyRefOS = 0x25, + File = 0x26, + ExportedType = 0x27, + ManifestResource = 0x28, + NestedClass = 0x29, + GenericParam = 0x2a, + MethodSpec = 0x2b, + GenericParamConstraint = 0x2c, + } + + struct TableInformation { + public uint Offset; + public uint Length; + public uint RowSize; + } + + sealed class TableHeap : Heap { + + public long Valid; + public long Sorted; + + public static readonly Table [] TableIdentifiers = new [] { + Table.Module, + Table.TypeRef, + Table.TypeDef, + Table.FieldPtr, + Table.Field, + Table.MethodPtr, + Table.Method, + Table.ParamPtr, + Table.Param, + Table.InterfaceImpl, + Table.MemberRef, + Table.Constant, + Table.CustomAttribute, + Table.FieldMarshal, + Table.DeclSecurity, + Table.ClassLayout, + Table.FieldLayout, + Table.StandAloneSig, + Table.EventMap, + Table.EventPtr, + Table.Event, + Table.PropertyMap, + Table.PropertyPtr, + Table.Property, + Table.MethodSemantics, + Table.MethodImpl, + Table.ModuleRef, + Table.TypeSpec, + Table.ImplMap, + Table.FieldRVA, + Table.Assembly, + Table.AssemblyProcessor, + Table.AssemblyOS, + Table.AssemblyRef, + Table.AssemblyRefProcessor, + Table.AssemblyRefOS, + Table.File, + Table.ExportedType, + Table.ManifestResource, + Table.NestedClass, + Table.GenericParam, + Table.MethodSpec, + Table.GenericParamConstraint, + }; + + public readonly TableInformation [] Tables = new TableInformation [45]; + + public TableInformation this [Table table] { + get { return Tables [(int) table]; } + } + + public TableHeap (Section section, uint start, uint size) + : base (section, start, size) + { + } + + public bool HasTable (Table table) + { + return (Valid & (1L << (int) table)) != 0; + } + } +} diff --git a/Mono.Cecil.Metadata/TokenType.cs b/Mono.Cecil.Metadata/TokenType.cs new file mode 100644 index 000000000..f822b6dd9 --- /dev/null +++ b/Mono.Cecil.Metadata/TokenType.cs @@ -0,0 +1,56 @@ +// +// TokenType.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace Mono.Cecil { + + public enum TokenType : uint { + Module = 0x00000000, + TypeRef = 0x01000000, + TypeDef = 0x02000000, + Field = 0x04000000, + Method = 0x06000000, + Param = 0x08000000, + InterfaceImpl = 0x09000000, + MemberRef = 0x0a000000, + CustomAttribute = 0x0c000000, + Permission = 0x0e000000, + Signature = 0x11000000, + Event = 0x14000000, + Property = 0x17000000, + ModuleRef = 0x1a000000, + TypeSpec = 0x1b000000, + Assembly = 0x20000000, + AssemblyRef = 0x23000000, + File = 0x26000000, + ExportedType = 0x27000000, + ManifestResource = 0x28000000, + GenericParam = 0x2a000000, + MethodSpec = 0x2b000000, + String = 0x70000000, + } +} diff --git a/Mono.Cecil.Metadata/UserStringHeap.cs b/Mono.Cecil.Metadata/UserStringHeap.cs new file mode 100644 index 000000000..7353cb705 --- /dev/null +++ b/Mono.Cecil.Metadata/UserStringHeap.cs @@ -0,0 +1,59 @@ +// +// UserStringHeap.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +using Mono.Cecil.PE; + +namespace Mono.Cecil.Metadata { + + sealed class UserStringHeap : StringHeap { + + public UserStringHeap (Section section, uint start, uint size) + : base (section, start, size) + { + } + + protected override string ReadStringAt (uint index) + { + byte [] data = Section.Data; + int start = (int) (index + Offset); + + uint length = (uint) (data.ReadCompressedUInt32 (ref start) & ~1); + if (length < 1) + return string.Empty; + + var chars = new char [length / 2]; + + for (int i = start, j = 0; i < start + length; i += 2) + chars [j++] = (char) (data [i] | (data [i + 1] << 8)); + + return new string (chars); + } + } +} diff --git a/Mono.Cecil.Metadata/Utilities.cs b/Mono.Cecil.Metadata/Utilities.cs new file mode 100644 index 000000000..496c61b51 --- /dev/null +++ b/Mono.Cecil.Metadata/Utilities.cs @@ -0,0 +1,529 @@ +// +// Utilities.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +using Mono.Cecil.Metadata; + +namespace Mono.Cecil { + + static partial class Mixin { + + public static uint ReadCompressedUInt32 (this byte [] data, ref int position) + { + uint integer; + if ((data [position] & 0x80) == 0) { + integer = data [position]; + position++; + } else if ((data [position] & 0x40) == 0) { + integer = (uint) (data [position] & ~0x80) << 8; + integer |= data [position + 1]; + position += 2; + } else { + integer = (uint) (data [position] & ~0xc0) << 24; + integer |= (uint) data [position + 1] << 16; + integer |= (uint) data [position + 2] << 8; + integer |= (uint) data [position + 3]; + position += 4; + } + return integer; + } + + public static MetadataToken GetMetadataToken (this CodedIndex self, uint data) + { + uint rid; + TokenType token_type; + switch (self) { + case CodedIndex.TypeDefOrRef: + rid = data >> 2; + switch (data & 3) { + case 0: + token_type = TokenType.TypeDef; goto ret; + case 1: + token_type = TokenType.TypeRef; goto ret; + case 2: + token_type = TokenType.TypeSpec; goto ret; + default: + goto exit; + } + case CodedIndex.HasConstant: + rid = data >> 2; + switch (data & 3) { + case 0: + token_type = TokenType.Field; goto ret; + case 1: + token_type = TokenType.Param; goto ret; + case 2: + token_type = TokenType.Property; goto ret; + default: + goto exit; + } + case CodedIndex.HasCustomAttribute: + rid = data >> 5; + switch (data & 31) { + case 0: + token_type = TokenType.Method; goto ret; + case 1: + token_type = TokenType.Field; goto ret; + case 2: + token_type = TokenType.TypeRef; goto ret; + case 3: + token_type = TokenType.TypeDef; goto ret; + case 4: + token_type = TokenType.Param; goto ret; + case 5: + token_type = TokenType.InterfaceImpl; goto ret; + case 6: + token_type = TokenType.MemberRef; goto ret; + case 7: + token_type = TokenType.Module; goto ret; + case 8: + token_type = TokenType.Permission; goto ret; + case 9: + token_type = TokenType.Property; goto ret; + case 10: + token_type = TokenType.Event; goto ret; + case 11: + token_type = TokenType.Signature; goto ret; + case 12: + token_type = TokenType.ModuleRef; goto ret; + case 13: + token_type = TokenType.TypeSpec; goto ret; + case 14: + token_type = TokenType.Assembly; goto ret; + case 15: + token_type = TokenType.AssemblyRef; goto ret; + case 16: + token_type = TokenType.File; goto ret; + case 17: + token_type = TokenType.ExportedType; goto ret; + case 18: + token_type = TokenType.ManifestResource; goto ret; + case 19: + token_type = TokenType.GenericParam; goto ret; + default: + goto exit; + } + case CodedIndex.HasFieldMarshal: + rid = data >> 1; + switch (data & 1) { + case 0: + token_type = TokenType.Field; goto ret; + case 1: + token_type = TokenType.Param; goto ret; + default: + goto exit; + } + case CodedIndex.HasDeclSecurity: + rid = data >> 2; + switch (data & 3) { + case 0: + token_type = TokenType.TypeDef; goto ret; + case 1: + token_type = TokenType.Method; goto ret; + case 2: + token_type = TokenType.Assembly; goto ret; + default: + goto exit; + } + case CodedIndex.MemberRefParent: + rid = data >> 3; + switch (data & 7) { + case 0: + token_type = TokenType.TypeDef; goto ret; + case 1: + token_type = TokenType.TypeRef; goto ret; + case 2: + token_type = TokenType.ModuleRef; goto ret; + case 3: + token_type = TokenType.Method; goto ret; + case 4: + token_type = TokenType.TypeSpec; goto ret; + default: + goto exit; + } + case CodedIndex.HasSemantics: + rid = data >> 1; + switch (data & 1) { + case 0: + token_type = TokenType.Event; goto ret; + case 1: + token_type = TokenType.Property; goto ret; + default: + goto exit; + } + case CodedIndex.MethodDefOrRef: + rid = data >> 1; + switch (data & 1) { + case 0: + token_type = TokenType.Method; goto ret; + case 1: + token_type = TokenType.MemberRef; goto ret; + default: + goto exit; + } + case CodedIndex.MemberForwarded: + rid = data >> 1; + switch (data & 1) { + case 0: + token_type = TokenType.Field; goto ret; + case 1: + token_type = TokenType.Method; goto ret; + default: + goto exit; + } + case CodedIndex.Implementation: + rid = data >> 2; + switch (data & 3) { + case 0: + token_type = TokenType.File; goto ret; + case 1: + token_type = TokenType.AssemblyRef; goto ret; + case 2: + token_type = TokenType.ExportedType; goto ret; + default: + goto exit; + } + case CodedIndex.CustomAttributeType: + rid = data >> 3; + switch (data & 7) { + case 2: + token_type = TokenType.Method; goto ret; + case 3: + token_type = TokenType.MemberRef; goto ret; + default: + goto exit; + } + case CodedIndex.ResolutionScope: + rid = data >> 2; + switch (data & 3) { + case 0: + token_type = TokenType.Module; goto ret; + case 1: + token_type = TokenType.ModuleRef; goto ret; + case 2: + token_type = TokenType.AssemblyRef; goto ret; + case 3: + token_type = TokenType.TypeRef; goto ret; + default: + goto exit; + } + case CodedIndex.TypeOrMethodDef: + rid = data >> 1; + switch (data & 1) { + case 0: + token_type = TokenType.TypeDef; goto ret; + case 1: + token_type = TokenType.Method; goto ret; + default: goto exit; + } + default: + goto exit; + } + ret: + return new MetadataToken (token_type, rid); + exit: + return MetadataToken.Zero; + } + +#if !READ_ONLY + public static uint CompressMetadataToken (this CodedIndex self, MetadataToken token) + { + uint ret = 0; + if (token.RID == 0) + return ret; + switch (self) { + case CodedIndex.TypeDefOrRef: + ret = token.RID << 2; + switch (token.TokenType) { + case TokenType.TypeDef: + return ret | 0; + case TokenType.TypeRef: + return ret | 1; + case TokenType.TypeSpec: + return ret | 2; + default: + goto exit; + } + case CodedIndex.HasConstant: + ret = token.RID << 2; + switch (token.TokenType) { + case TokenType.Field: + return ret | 0; + case TokenType.Param: + return ret | 1; + case TokenType.Property: + return ret | 2; + default: + goto exit; + } + case CodedIndex.HasCustomAttribute: + ret = token.RID << 5; + switch (token.TokenType) { + case TokenType.Method: + return ret | 0; + case TokenType.Field: + return ret | 1; + case TokenType.TypeRef: + return ret | 2; + case TokenType.TypeDef: + return ret | 3; + case TokenType.Param: + return ret | 4; + case TokenType.InterfaceImpl: + return ret | 5; + case TokenType.MemberRef: + return ret | 6; + case TokenType.Module: + return ret | 7; + case TokenType.Permission: + return ret | 8; + case TokenType.Property: + return ret | 9; + case TokenType.Event: + return ret | 10; + case TokenType.Signature: + return ret | 11; + case TokenType.ModuleRef: + return ret | 12; + case TokenType.TypeSpec: + return ret | 13; + case TokenType.Assembly: + return ret | 14; + case TokenType.AssemblyRef: + return ret | 15; + case TokenType.File: + return ret | 16; + case TokenType.ExportedType: + return ret | 17; + case TokenType.ManifestResource: + return ret | 18; + case TokenType.GenericParam: + return ret | 19; + default: + goto exit; + } + case CodedIndex.HasFieldMarshal: + ret = token.RID << 1; + switch (token.TokenType) { + case TokenType.Field: + return ret | 0; + case TokenType.Param: + return ret | 1; + default: + goto exit; + } + case CodedIndex.HasDeclSecurity: + ret = token.RID << 2; + switch (token.TokenType) { + case TokenType.TypeDef: + return ret | 0; + case TokenType.Method: + return ret | 1; + case TokenType.Assembly: + return ret | 2; + default: + goto exit; + } + case CodedIndex.MemberRefParent: + ret = token.RID << 3; + switch (token.TokenType) { + case TokenType.TypeDef: + return ret | 0; + case TokenType.TypeRef: + return ret | 1; + case TokenType.ModuleRef: + return ret | 2; + case TokenType.Method: + return ret | 3; + case TokenType.TypeSpec: + return ret | 4; + default: + goto exit; + } + case CodedIndex.HasSemantics: + ret = token.RID << 1; + switch (token.TokenType) { + case TokenType.Event: + return ret | 0; + case TokenType.Property: + return ret | 1; + default: + goto exit; + } + case CodedIndex.MethodDefOrRef: + ret = token.RID << 1; + switch (token.TokenType) { + case TokenType.Method: + return ret | 0; + case TokenType.MemberRef: + return ret | 1; + default: + goto exit; + } + case CodedIndex.MemberForwarded: + ret = token.RID << 1; + switch (token.TokenType) { + case TokenType.Field: + return ret | 0; + case TokenType.Method: + return ret | 1; + default: + goto exit; + } + case CodedIndex.Implementation: + ret = token.RID << 2; + switch (token.TokenType) { + case TokenType.File: + return ret | 0; + case TokenType.AssemblyRef: + return ret | 1; + case TokenType.ExportedType: + return ret | 2; + default: + goto exit; + } + case CodedIndex.CustomAttributeType: + ret = token.RID << 3; + switch (token.TokenType) { + case TokenType.Method: + return ret | 2; + case TokenType.MemberRef: + return ret | 3; + default: + goto exit; + } + case CodedIndex.ResolutionScope: + ret = token.RID << 2; + switch (token.TokenType) { + case TokenType.Module: + return ret | 0; + case TokenType.ModuleRef: + return ret | 1; + case TokenType.AssemblyRef: + return ret | 2; + case TokenType.TypeRef: + return ret | 3; + default: + goto exit; + } + case CodedIndex.TypeOrMethodDef: + ret = token.RID << 1; + switch (token.TokenType) { + case TokenType.TypeDef: + return ret | 0; + case TokenType.Method: + return ret | 1; + default: + goto exit; + } + default: + goto exit; + } + exit: + throw new ArgumentException (); + } +#endif + + public static int GetSize (this CodedIndex self, Func counter) + { + int bits; + Table [] tables; + + switch (self) { + case CodedIndex.TypeDefOrRef: + bits = 2; + tables = new [] { Table.TypeDef, Table.TypeRef, Table.TypeSpec }; + break; + case CodedIndex.HasConstant: + bits = 2; + tables = new [] { Table.Field, Table.Param, Table.Property }; + break; + case CodedIndex.HasCustomAttribute: + bits = 5; + tables = new [] { + Table.Method, Table.Field, Table.TypeRef, Table.TypeDef, Table.Param, Table.InterfaceImpl, Table.MemberRef, + Table.Module, Table.DeclSecurity, Table.Property, Table.Event, Table.StandAloneSig, Table.ModuleRef, + Table.TypeSpec, Table.Assembly, Table.AssemblyRef, Table.File, Table.ExportedType, + Table.ManifestResource, Table.GenericParam + }; + break; + case CodedIndex.HasFieldMarshal: + bits = 1; + tables = new [] { Table.Field, Table.Param }; + break; + case CodedIndex.HasDeclSecurity: + bits = 2; + tables = new [] { Table.TypeDef, Table.Method, Table.Assembly }; + break; + case CodedIndex.MemberRefParent: + bits = 3; + tables = new [] { Table.TypeDef, Table.TypeRef, Table.ModuleRef, Table.Method, Table.TypeSpec }; + break; + case CodedIndex.HasSemantics: + bits = 1; + tables = new [] { Table.Event, Table.Property }; + break; + case CodedIndex.MethodDefOrRef: + bits = 1; + tables = new [] { Table.Method, Table.MemberRef }; + break; + case CodedIndex.MemberForwarded: + bits = 1; + tables = new [] { Table.Field, Table.Method }; + break; + case CodedIndex.Implementation: + bits = 2; + tables = new [] { Table.File, Table.AssemblyRef, Table.ExportedType }; + break; + case CodedIndex.CustomAttributeType: + bits = 3; + tables = new [] { Table.Method, Table.MemberRef }; + break; + case CodedIndex.ResolutionScope: + bits = 2; + tables = new [] { Table.Module, Table.ModuleRef, Table.AssemblyRef, Table.TypeRef }; + break; + case CodedIndex.TypeOrMethodDef: + bits = 1; + tables = new [] { Table.TypeDef, Table.Method }; + break; + default: + throw new ArgumentException (); + } + + int max = 0; + + for (int i = 0; i < tables.Length; i++) { + max = System.Math.Max (counter (tables [i]), max); + } + + return max < (1 << (16 - bits)) ? 2 : 4; + } + } +} diff --git a/Mono.Cecil.PE/BinaryStreamReader.cs b/Mono.Cecil.PE/BinaryStreamReader.cs new file mode 100644 index 000000000..8f5b38e16 --- /dev/null +++ b/Mono.Cecil.PE/BinaryStreamReader.cs @@ -0,0 +1,51 @@ +// +// BinaryStreamReader.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.IO; + +namespace Mono.Cecil.PE { + + class BinaryStreamReader : BinaryReader { + + public BinaryStreamReader (Stream stream) + : base (stream) + { + } + + protected void Advance (int bytes) + { + BaseStream.Seek (bytes, SeekOrigin.Current); + } + + protected DataDirectory ReadDataDirectory () + { + return new DataDirectory (ReadUInt32 (), ReadUInt32 ()); + } + } +} diff --git a/Mono.Cecil.PE/BinaryStreamWriter.cs b/Mono.Cecil.PE/BinaryStreamWriter.cs new file mode 100644 index 000000000..37189cb66 --- /dev/null +++ b/Mono.Cecil.PE/BinaryStreamWriter.cs @@ -0,0 +1,96 @@ +// +// BinaryStreamWriter.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.IO; + +#if !READ_ONLY + +namespace Mono.Cecil.PE { + + class BinaryStreamWriter : BinaryWriter { + + public BinaryStreamWriter (Stream stream) + : base (stream) + { + } + + public void WriteByte (byte value) + { + Write (value); + } + + public void WriteUInt16 (ushort value) + { + Write (value); + } + + public void WriteInt16 (short value) + { + Write (value); + } + + public void WriteUInt32 (uint value) + { + Write (value); + } + + public void WriteInt32 (int value) + { + Write (value); + } + + public void WriteUInt64 (ulong value) + { + Write (value); + } + + public void WriteBytes (byte [] bytes) + { + Write (bytes); + } + + public void WriteDataDirectory (DataDirectory directory) + { + Write (directory.VirtualAddress); + Write (directory.Size); + } + + public void WriteBuffer (ByteBuffer buffer) + { + Write (buffer.buffer, 0, buffer.length); + } + + protected void Advance (int bytes) + { + BaseStream.Seek (bytes, SeekOrigin.Current); + } + } +} + +#endif diff --git a/Mono.Cecil.PE/ByteBuffer.cs b/Mono.Cecil.PE/ByteBuffer.cs new file mode 100644 index 000000000..4303b6d56 --- /dev/null +++ b/Mono.Cecil.PE/ByteBuffer.cs @@ -0,0 +1,342 @@ +// +// ByteBuffer.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace Mono.Cecil.PE { + + class ByteBuffer { + + internal byte [] buffer; + internal int length; + internal int position; + + public ByteBuffer () + { + this.buffer = Empty.Array; + } + + public ByteBuffer (int length) + { + this.buffer = new byte [length]; + } + + public ByteBuffer (byte [] buffer) + { + this.buffer = buffer ?? Empty.Array; + this.length = this.buffer.Length; + } + + public void Reset (byte [] buffer) + { + this.buffer = buffer ?? Empty.Array; + this.length = this.buffer.Length; + } + + public void Advance (int length) + { + position += length; + } + + public byte ReadByte () + { + return buffer [position++]; + } + + public sbyte ReadSByte () + { + return (sbyte) ReadByte (); + } + + public byte [] ReadBytes (int length) + { + var bytes = new byte [length]; + Buffer.BlockCopy (buffer, position, bytes, 0, length); + position += length; + return bytes; + } + + public ushort ReadUInt16 () + { + ushort value = (ushort) (buffer [position] + | (buffer [position + 1] << 8)); + position += 2; + return value; + } + + public short ReadInt16 () + { + return (short) ReadUInt16 (); + } + + public uint ReadUInt32 () + { + uint value = (uint) (buffer [position] + | (buffer [position + 1] << 8) + | (buffer [position + 2] << 16) + | (buffer [position + 3] << 24)); + position += 4; + return value; + } + + public int ReadInt32 () + { + return (int) ReadUInt32 (); + } + + public ulong ReadUInt64 () + { + uint low = ReadUInt32 (); + uint high = ReadUInt32 (); + + return (((ulong) high) << 32) | low; + } + + public long ReadInt64 () + { + return (long) ReadUInt64 (); + } + + public uint ReadCompressedUInt32 () + { + byte first = ReadByte (); + if ((first & 0x80) == 0) + return first; + + if ((first & 0x40) == 0) + return ((uint) (first & ~0x80) << 8) + | ReadByte (); + + return ((uint) (first & ~0xc0) << 24) + | (uint) ReadByte () << 16 + | (uint) ReadByte () << 8 + | ReadByte (); + } + + public int ReadCompressedInt32 () + { + var value = (int) ReadCompressedUInt32 (); + + return (value & 1) != 0 + ? -(value >> 1) + : value >> 1; + } + + public float ReadSingle () + { + if (!BitConverter.IsLittleEndian) { + var bytes = ReadBytes (4); + Array.Reverse (bytes); + return BitConverter.ToSingle (bytes, 0); + } + + float value = BitConverter.ToSingle (buffer, position); + position += 4; + return value; + } + + public double ReadDouble () + { + if (!BitConverter.IsLittleEndian) { + var bytes = ReadBytes (8); + Array.Reverse (bytes); + return BitConverter.ToDouble (bytes, 0); + } + + double value = BitConverter.ToDouble (buffer, position); + position += 8; + return value; + } + +#if !READ_ONLY + + public void WriteByte (byte value) + { + if (position == buffer.Length) + Grow (1); + + buffer [position++] = value; + + if (position > length) + length = position; + } + + public void WriteSByte (sbyte value) + { + WriteByte ((byte) value); + } + + public void WriteUInt16 (ushort value) + { + if (position + 2 > buffer.Length) + Grow (2); + + buffer [position++] = (byte) value; + buffer [position++] = (byte) (value >> 8); + + if (position > length) + length = position; + } + + public void WriteInt16 (short value) + { + WriteUInt16 ((ushort) value); + } + + public void WriteUInt32 (uint value) + { + if (position + 4 > buffer.Length) + Grow (4); + + buffer [position++] = (byte) value; + buffer [position++] = (byte) (value >> 8); + buffer [position++] = (byte) (value >> 16); + buffer [position++] = (byte) (value >> 24); + + if (position > length) + length = position; + } + + public void WriteInt32 (int value) + { + WriteUInt32 ((uint) value); + } + + public void WriteUInt64 (ulong value) + { + if (position + 8 > buffer.Length) + Grow (8); + + buffer [position++] = (byte) value; + buffer [position++] = (byte) (value >> 8); + buffer [position++] = (byte) (value >> 16); + buffer [position++] = (byte) (value >> 24); + buffer [position++] = (byte) (value >> 32); + buffer [position++] = (byte) (value >> 40); + buffer [position++] = (byte) (value >> 48); + buffer [position++] = (byte) (value >> 56); + + if (position > length) + length = position; + } + + public void WriteInt64 (long value) + { + WriteUInt64 ((ulong) value); + } + + public void WriteCompressedUInt32 (uint value) + { + if (value < 0x80) + WriteByte ((byte) value); + else if (value < 0x4000) { + WriteByte ((byte) (0x80 | (value >> 8))); + WriteByte ((byte) (value & 0xff)); + } else { + WriteByte ((byte) ((value >> 24) | 0xc0)); + WriteByte ((byte) ((value >> 16) & 0xff)); + WriteByte ((byte) ((value >> 8) & 0xff)); + WriteByte ((byte) (value & 0xff)); + } + } + + public void WriteCompressedInt32 (int value) + { + WriteCompressedUInt32 ((uint) ((value < 0) ? ((-value) << 1) | 1 : value << 1)); + } + + public void WriteBytes (byte [] bytes) + { + var length = bytes.Length; + if (position + length > buffer.Length) + Grow (length); + + Buffer.BlockCopy (bytes, 0, buffer, position, length); + position += length; + + if (position > this.length) + this.length = position; + } + + public void WriteBytes (int length) + { + if (position + length > buffer.Length) + Grow (length); + + position += length; + + if (position > this.length) + this.length = position; + } + + public void WriteBytes (ByteBuffer buffer) + { + if (position + buffer.length > this.buffer.Length) + Grow (buffer.length); + + Buffer.BlockCopy (buffer.buffer, 0, this.buffer, position, buffer.length); + position += buffer.length; + + if (position > this.length) + this.length = position; + } + + public void WriteSingle (float value) + { + var bytes = BitConverter.GetBytes (value); + + if (!BitConverter.IsLittleEndian) + Array.Reverse (bytes); + + WriteBytes (bytes); + } + + public void WriteDouble (double value) + { + var bytes = BitConverter.GetBytes (value); + + if (!BitConverter.IsLittleEndian) + Array.Reverse (bytes); + + WriteBytes (bytes); + } + + void Grow (int desired) + { + var current = this.buffer; + var current_length = current.Length; + + var buffer = new byte [System.Math.Max (current_length + desired, current_length * 2)]; + Buffer.BlockCopy (current, 0, buffer, 0, current_length); + this.buffer = buffer; + } + +#endif + + } +} diff --git a/Mono.Cecil.PE/ByteBufferEqualityComparer.cs b/Mono.Cecil.PE/ByteBufferEqualityComparer.cs new file mode 100644 index 000000000..fe56a6f18 --- /dev/null +++ b/Mono.Cecil.PE/ByteBufferEqualityComparer.cs @@ -0,0 +1,78 @@ +// +// ByteBufferEqualityComparer.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Generic; + +namespace Mono.Cecil.PE { + + sealed class ByteBufferEqualityComparer : IEqualityComparer { + + public bool Equals (ByteBuffer x, ByteBuffer y) + { + if (x.length != y.length) + return false; + + var x_buffer = x.buffer; + var y_buffer = y.buffer; + + for (int i = 0; i < x.length; i++) + if (x_buffer [i] != y_buffer [i]) + return false; + + return true; + } + + public int GetHashCode (ByteBuffer buffer) + { +#if !BYTE_BUFFER_WELL_DISTRIBUTED_HASH + var hash = 0; + var bytes = buffer.buffer; + for (int i = 0; i < buffer.length; i++) + hash = (hash * 37) ^ bytes [i]; + + return hash; +#else + const uint p = 16777619; + uint hash = 2166136261; + + var bytes = buffer.buffer; + for (int i = 0; i < buffer.length; i++) + hash = (hash ^ bytes [i]) * p; + + hash += hash << 13; + hash ^= hash >> 7; + hash += hash << 3; + hash ^= hash >> 17; + hash += hash << 5; + + return (int) hash; +#endif + } + } +} diff --git a/Mono.Cecil.PE/DataDirectory.cs b/Mono.Cecil.PE/DataDirectory.cs new file mode 100644 index 000000000..5ba2d2d55 --- /dev/null +++ b/Mono.Cecil.PE/DataDirectory.cs @@ -0,0 +1,50 @@ +// +// DataDirectory.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +using RVA = System.UInt32; + +namespace Mono.Cecil.PE { + + struct DataDirectory { + + public readonly RVA VirtualAddress; + public readonly uint Size; + + public bool IsZero { + get { return VirtualAddress == 0 && Size == 0; } + } + + public DataDirectory (RVA rva, uint size) + { + this.VirtualAddress = rva; + this.Size = size; + } + } +} diff --git a/Mono.Cecil.PE/Image.cs b/Mono.Cecil.PE/Image.cs new file mode 100644 index 000000000..11aba8fd2 --- /dev/null +++ b/Mono.Cecil.PE/Image.cs @@ -0,0 +1,159 @@ +// +// Image.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +using Mono; +using Mono.Cecil.Cil; +using Mono.Cecil.Metadata; + +using RVA = System.UInt32; + +namespace Mono.Cecil.PE { + + sealed class Image { + + public ModuleKind Kind; + public TargetRuntime Runtime; + public TargetArchitecture Architecture; + public string FileName; + + public Section [] Sections; + + public Section MetadataSection; + + public uint EntryPointToken; + public ModuleAttributes Attributes; + + public DataDirectory Debug; + public DataDirectory Resources; + + public StringHeap StringHeap; + public BlobHeap BlobHeap; + public UserStringHeap UserStringHeap; + public GuidHeap GuidHeap; + public TableHeap TableHeap; + + readonly int [] coded_index_sizes = new int [13]; + + readonly Func counter; + + public Image () + { + counter = GetTableLength; + } + + public bool HasTable (Table table) + { + return GetTableLength (table) > 0; + } + + public int GetTableLength (Table table) + { + return (int) TableHeap [table].Length; + } + + public int GetTableIndexSize (Table table) + { + return GetTableLength (table) < 65536 ? 2 : 4; + } + + public int GetCodedIndexSize (CodedIndex coded_index) + { + var index = (int) coded_index; + var size = coded_index_sizes [index]; + if (size != 0) + return size; + + return coded_index_sizes [index] = coded_index.GetSize (counter); + } + + public uint ResolveVirtualAddress (RVA rva) + { + var section = GetSectionAtVirtualAddress (rva); + if (section == null) + throw new ArgumentOutOfRangeException (); + + return ResolveVirtualAddressInSection (rva, section); + } + + public uint ResolveVirtualAddressInSection (RVA rva, Section section) + { + return rva + section.PointerToRawData - section.VirtualAddress; + } + + public Section GetSection (string name) + { + var sections = this.Sections; + for (int i = 0; i < sections.Length; i++) { + var section = sections [i]; + if (section.Name == name) + return section; + } + + return null; + } + + public Section GetSectionAtVirtualAddress (RVA rva) + { + var sections = this.Sections; + for (int i = 0; i < sections.Length; i++) { + var section = sections [i]; + if (rva >= section.VirtualAddress && rva < section.VirtualAddress + section.SizeOfRawData) + return section; + } + + return null; + } + + public ImageDebugDirectory GetDebugHeader (out byte [] header) + { + var section = GetSectionAtVirtualAddress (Debug.VirtualAddress); + var buffer = new ByteBuffer (section.Data); + buffer.position = (int) (Debug.VirtualAddress - section.VirtualAddress); + + var directory = new ImageDebugDirectory { + Characteristics = buffer.ReadInt32 (), + TimeDateStamp = buffer.ReadInt32 (), + MajorVersion = buffer.ReadInt16 (), + MinorVersion = buffer.ReadInt16 (), + Type = buffer.ReadInt32 (), + SizeOfData = buffer.ReadInt32 (), + AddressOfRawData = buffer.ReadInt32 (), + PointerToRawData = buffer.ReadInt32 (), + }; + + buffer.position = (int) (directory.PointerToRawData - section.PointerToRawData); + + header = new byte [directory.SizeOfData]; + Buffer.BlockCopy (buffer.buffer, buffer.position, header, 0, header.Length); + + return directory; + } + } +} diff --git a/Mono.Cecil.PE/ImageReader.cs b/Mono.Cecil.PE/ImageReader.cs new file mode 100644 index 000000000..a228c1ffe --- /dev/null +++ b/Mono.Cecil.PE/ImageReader.cs @@ -0,0 +1,678 @@ +// +// ImageReader.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.IO; + +using Mono.Cecil.Metadata; + +using RVA = System.UInt32; + +namespace Mono.Cecil.PE { + + sealed class ImageReader : BinaryStreamReader { + + readonly Image image; + + DataDirectory cli; + DataDirectory metadata; + + public ImageReader (Stream stream) + : base (stream) + { + image = new Image (); + + image.FileName = stream.GetFullyQualifiedName (); + } + + void MoveTo (DataDirectory directory) + { + BaseStream.Position = image.ResolveVirtualAddress (directory.VirtualAddress); + } + + void MoveTo (uint position) + { + BaseStream.Position = position; + } + + void ReadImage () + { + if (BaseStream.Length < 128) + throw new BadImageFormatException (); + + // - DOSHeader + + // PE 2 + // Start 58 + // Lfanew 4 + // End 64 + + if (ReadUInt16 () != 0x5a4d) + throw new BadImageFormatException (); + + Advance (58); + + MoveTo (ReadUInt32 ()); + + if (ReadUInt32 () != 0x00004550) + throw new BadImageFormatException (); + + // - PEFileHeader + + // Machine 2 + image.Architecture = ReadArchitecture (); + + // NumberOfSections 2 + ushort sections = ReadUInt16 (); + + // TimeDateStamp 4 + // PointerToSymbolTable 4 + // NumberOfSymbols 4 + // OptionalHeaderSize 2 + Advance (14); + + // Characteristics 2 + ushort characteristics = ReadUInt16 (); + + ushort subsystem; + ReadOptionalHeaders (out subsystem); + ReadSections (sections); + ReadCLIHeader (); + ReadMetadata (); + + image.Kind = GetModuleKind (characteristics, subsystem); + } + + TargetArchitecture ReadArchitecture () + { + var machine = ReadUInt16 (); + switch (machine) { + case 0x014c: + return TargetArchitecture.I386; + case 0x8664: + return TargetArchitecture.AMD64; + case 0x0200: + return TargetArchitecture.IA64; + } + + throw new NotSupportedException (); + } + + static ModuleKind GetModuleKind (ushort characteristics, ushort subsystem) + { + if ((characteristics & 0x2000) != 0) // ImageCharacteristics.Dll + return ModuleKind.Dll; + + if (subsystem == 0x2 || subsystem == 0x9) // SubSystem.WindowsGui || SubSystem.WindowsCeGui + return ModuleKind.Windows; + + return ModuleKind.Console; + } + + void ReadOptionalHeaders (out ushort subsystem) + { + // - PEOptionalHeader + // - StandardFieldsHeader + + // Magic 2 + bool pe64 = ReadUInt16 () == 0x20b; + + // pe32 || pe64 + + // LMajor 1 + // LMinor 1 + // CodeSize 4 + // InitializedDataSize 4 + // UninitializedDataSize4 + // EntryPointRVA 4 + // BaseOfCode 4 + // BaseOfData 4 || 0 + + // - NTSpecificFieldsHeader + + // ImageBase 4 || 8 + // SectionAlignment 4 + // FileAlignement 4 + // OSMajor 2 + // OSMinor 2 + // UserMajor 2 + // UserMinor 2 + // SubSysMajor 2 + // SubSysMinor 2 + // Reserved 4 + // ImageSize 4 + // HeaderSize 4 + // FileChecksum 4 + Advance (66); + + // SubSystem 2 + subsystem = ReadUInt16 (); + + // DLLFlags 2 + // StackReserveSize 4 || 8 + // StackCommitSize 4 || 8 + // HeapReserveSize 4 || 8 + // HeapCommitSize 4 || 8 + // LoaderFlags 4 + // NumberOfDataDir 4 + + // - DataDirectoriesHeader + + // ExportTable 8 + // ImportTable 8 + // ResourceTable 8 + // ExceptionTable 8 + // CertificateTable 8 + // BaseRelocationTable 8 + + Advance (pe64 ? 90 : 74); + + // Debug 8 + image.Debug = ReadDataDirectory (); + + // Copyright 8 + // GlobalPtr 8 + // TLSTable 8 + // LoadConfigTable 8 + // BoundImport 8 + // IAT 8 + // DelayImportDescriptor8 + Advance (56); + + // CLIHeader 8 + cli = ReadDataDirectory (); + + if (cli.IsZero) + throw new BadImageFormatException (); + + // Reserved 8 + Advance (8); + } + + string ReadAlignedString (int length) + { + int read = 0; + var buffer = new char [length]; + while (read < length) { + var current = ReadByte (); + if (current == 0) + break; + + buffer [read++] = (char) current; + } + + Advance (-1 + ((read + 4) & ~3) - read); + + return new string (buffer, 0, read); + } + + string ReadZeroTerminatedString (int length) + { + int read = 0; + var buffer = new char [length]; + var bytes = ReadBytes (length); + while (read < length) { + var current = bytes [read]; + if (current == 0) + break; + + buffer [read++] = (char) current; + } + + return new string (buffer, 0, read); + } + + void ReadSections (ushort count) + { + var sections = new Section [count]; + + for (int i = 0; i < count; i++) { + var section = new Section (); + + // Name + section.Name = ReadZeroTerminatedString (8); + + // VirtualSize 4 + Advance (4); + + // VirtualAddress 4 + section.VirtualAddress = ReadUInt32 (); + // SizeOfRawData 4 + section.SizeOfRawData = ReadUInt32 (); + // PointerToRawData 4 + section.PointerToRawData = ReadUInt32 (); + + // PointerToRelocations 4 + // PointerToLineNumbers 4 + // NumberOfRelocations 2 + // NumberOfLineNumbers 2 + // Characteristics 4 + Advance (16); + + sections [i] = section; + + if (section.Name == ".reloc") + continue; + + ReadSectionData (section); + } + + image.Sections = sections; + } + + void ReadSectionData (Section section) + { + var position = BaseStream.Position; + + MoveTo (section.PointerToRawData); + + var length = (int) section.SizeOfRawData; + var data = new byte [length]; + int offset = 0, read; + + while ((read = Read (data, offset, length - offset)) > 0) + offset += read; + + section.Data = data; + + BaseStream.Position = position; + } + + void ReadCLIHeader () + { + MoveTo (cli); + + // - CLIHeader + + // Cb 4 + // MajorRuntimeVersion 2 + // MinorRuntimeVersion 2 + Advance (8); + + // Metadata 8 + metadata = ReadDataDirectory (); + // Flags 4 + image.Attributes = (ModuleAttributes) ReadUInt32 (); + // EntryPointToken 4 + image.EntryPointToken = ReadUInt32 (); + // Resources 8 + image.Resources = ReadDataDirectory (); + // StrongNameSignature 8 + // CodeManagerTable 8 + // VTableFixups 8 + // ExportAddressTableJumps 8 + // ManagedNativeHeader 8 + } + + void ReadMetadata () + { + MoveTo (metadata); + + if (ReadUInt32 () != 0x424a5342) + throw new BadImageFormatException (); + + // MajorVersion 2 + // MinorVersion 2 + // Reserved 4 + Advance (8); + + var version = ReadZeroTerminatedString (ReadInt32 ()); + image.Runtime = version.ParseRuntime (); + + // Flags 2 + Advance (2); + + var streams = ReadUInt16 (); + + var section = image.GetSectionAtVirtualAddress (metadata.VirtualAddress); + if (section == null) + throw new BadImageFormatException (); + + image.MetadataSection = section; + + for (int i = 0; i < streams; i++) + ReadMetadataStream (section); + + if (image.TableHeap != null) + ReadTableHeap (); + } + + void ReadMetadataStream (Section section) + { + // Offset 4 + uint start = metadata.VirtualAddress - section.VirtualAddress + ReadUInt32 (); // relative to the section start + + // Size 4 + uint size = ReadUInt32 (); + + var name = ReadAlignedString (16); + switch (name) { + case "#~": + case "#-": + image.TableHeap = new TableHeap (section, start, size); + break; + case "#Strings": + image.StringHeap = new StringHeap (section, start, size); + break; + case "#Blob": + image.BlobHeap = new BlobHeap (section, start, size); + break; + case "#GUID": + image.GuidHeap = new GuidHeap (section, start, size); + break; + case "#US": + image.UserStringHeap = new UserStringHeap (section, start, size); + break; + } + } + + void ReadTableHeap () + { + var heap = image.TableHeap; + + uint start = heap.Section.PointerToRawData; + + MoveTo (heap.Offset + start); + + // Reserved 4 + // MajorVersion 1 + // MinorVersion 1 + Advance (6); + + // HeapSizes 1 + var sizes = ReadByte (); + + // Reserved2 1 + Advance (1); + + // Valid 8 + heap.Valid = ReadInt64 (); + + // Sorted 8 + heap.Sorted = ReadInt64 (); + + for (int i = 0; i < TableHeap.TableIdentifiers.Length; i++) { + var table = TableHeap.TableIdentifiers [i]; + if (!heap.HasTable (table)) + continue; + + heap.Tables [(int) table].Length = ReadUInt32 (); + } + + SetIndexSize (image.StringHeap, sizes, 0x1); + SetIndexSize (image.GuidHeap, sizes, 0x2); + SetIndexSize (image.BlobHeap, sizes, 0x4); + + ComputeTableInformations (); + } + + static void SetIndexSize (Heap heap, uint sizes, byte flag) + { + if (heap == null) + return; + + heap.IndexSize = (sizes & flag) > 0 ? 4 : 2; + } + + int GetTableIndexSize (Table table) + { + return image.GetTableIndexSize (table); + } + + int GetCodedIndexSize (CodedIndex index) + { + return image.GetCodedIndexSize (index); + } + + void ComputeTableInformations () + { + uint offset = (uint) BaseStream.Position - image.MetadataSection.PointerToRawData; // header + + int stridx_size = image.StringHeap.IndexSize; + int blobidx_size = image.BlobHeap != null ? image.BlobHeap.IndexSize : 2; + + var heap = image.TableHeap; + var tables = heap.Tables; + + for (int i = 0; i < TableHeap.TableIdentifiers.Length; i++) { + var table = TableHeap.TableIdentifiers [i]; + if (!heap.HasTable (table)) + continue; + + int size; + switch (table) { + case Table.Module: + size = 2 // Generation + + stridx_size // Name + + (image.GuidHeap.IndexSize * 3); // Mvid, EncId, EncBaseId + break; + case Table.TypeRef: + size = GetCodedIndexSize (CodedIndex.ResolutionScope) // ResolutionScope + + (stridx_size * 2); // Name, Namespace + break; + case Table.TypeDef: + size = 4 // Flags + + (stridx_size * 2) // Name, Namespace + + GetCodedIndexSize (CodedIndex.TypeDefOrRef) // BaseType + + GetTableIndexSize (Table.Field) // FieldList + + GetTableIndexSize (Table.Method); // MethodList + break; + case Table.FieldPtr: + size = GetTableIndexSize (Table.Field); // Field + break; + case Table.Field: + size = 2 // Flags + + stridx_size // Name + + blobidx_size; // Signature + break; + case Table.MethodPtr: + size = GetTableIndexSize (Table.Method); // Method + break; + case Table.Method: + size = 8 // Rva 4, ImplFlags 2, Flags 2 + + stridx_size // Name + + blobidx_size // Signature + + GetTableIndexSize (Table.Param); // ParamList + break; + case Table.ParamPtr: + size = GetTableIndexSize (Table.Param); // Param + break; + case Table.Param: + size = 4 // Flags 2, Sequence 2 + + stridx_size; // Name + break; + case Table.InterfaceImpl: + size = GetTableIndexSize (Table.TypeDef) // Class + + GetCodedIndexSize (CodedIndex.TypeDefOrRef); // Interface + break; + case Table.MemberRef: + size = GetCodedIndexSize (CodedIndex.MemberRefParent) // Class + + stridx_size // Name + + blobidx_size; // Signature + break; + case Table.Constant: + size = 2 // Type + + GetCodedIndexSize (CodedIndex.HasConstant) // Parent + + blobidx_size; // Value + break; + case Table.CustomAttribute: + size = GetCodedIndexSize (CodedIndex.HasCustomAttribute) // Parent + + GetCodedIndexSize (CodedIndex.CustomAttributeType) // Type + + blobidx_size; // Value + break; + case Table.FieldMarshal: + size = GetCodedIndexSize (CodedIndex.HasFieldMarshal) // Parent + + blobidx_size; // NativeType + break; + case Table.DeclSecurity: + size = 2 // Action + + GetCodedIndexSize (CodedIndex.HasDeclSecurity) // Parent + + blobidx_size; // PermissionSet + break; + case Table.ClassLayout: + size = 6 // PackingSize 2, ClassSize 4 + + GetTableIndexSize (Table.TypeDef); // Parent + break; + case Table.FieldLayout: + size = 4 // Offset + + GetTableIndexSize (Table.Field); // Field + break; + case Table.StandAloneSig: + size = blobidx_size; // Signature + break; + case Table.EventMap: + size = GetTableIndexSize (Table.TypeDef) // Parent + + GetTableIndexSize (Table.Event); // EventList + break; + case Table.EventPtr: + size = GetTableIndexSize (Table.Event); // Event + break; + case Table.Event: + size = 2 // Flags + + stridx_size // Name + + GetCodedIndexSize (CodedIndex.TypeDefOrRef); // EventType + break; + case Table.PropertyMap: + size = GetTableIndexSize (Table.TypeDef) // Parent + + GetTableIndexSize (Table.Property); // PropertyList + break; + case Table.PropertyPtr: + size = GetTableIndexSize (Table.Property); // Property + break; + case Table.Property: + size = 2 // Flags + + stridx_size // Name + + blobidx_size; // Type + break; + case Table.MethodSemantics: + size = 2 // Semantics + + GetTableIndexSize (Table.Method) // Method + + GetCodedIndexSize (CodedIndex.HasSemantics); // Association + break; + case Table.MethodImpl: + size = GetTableIndexSize (Table.TypeDef) // Class + + GetCodedIndexSize (CodedIndex.MethodDefOrRef) // MethodBody + + GetCodedIndexSize (CodedIndex.MethodDefOrRef); // MethodDeclaration + break; + case Table.ModuleRef: + size = stridx_size; // Name + break; + case Table.TypeSpec: + size = blobidx_size; // Signature + break; + case Table.ImplMap: + size = 2 // MappingFlags + + GetCodedIndexSize (CodedIndex.MemberForwarded) // MemberForwarded + + stridx_size // ImportName + + GetTableIndexSize (Table.ModuleRef); // ImportScope + break; + case Table.FieldRVA: + size = 4 // RVA + + GetTableIndexSize (Table.Field); // Field + break; + case Table.Assembly: + size = 16 // HashAlgId 4, Version 4 * 2, Flags 4 + + blobidx_size // PublicKey + + (stridx_size * 2); // Name, Culture + break; + case Table.AssemblyProcessor: + size = 4; // Processor + break; + case Table.AssemblyOS: + size = 12; // Platform 4, Version 2 * 4 + break; + case Table.AssemblyRef: + size = 12 // Version 2 * 4 + Flags 4 + + (blobidx_size * 2) // PublicKeyOrToken, HashValue + + (stridx_size * 2); // Name, Culture + break; + case Table.AssemblyRefProcessor: + size = 4 // Processor + + GetTableIndexSize (Table.AssemblyRef); // AssemblyRef + break; + case Table.AssemblyRefOS: + size = 12 // Platform 4, Version 2 * 4 + + GetTableIndexSize (Table.AssemblyRef); // AssemblyRef + break; + case Table.File: + size = 4 // Flags + + stridx_size // Name + + blobidx_size; // HashValue + break; + case Table.ExportedType: + size = 8 // Flags 4, TypeDefId 4 + + (stridx_size * 2) // Name, Namespace + + GetCodedIndexSize (CodedIndex.Implementation); // Implementation + break; + case Table.ManifestResource: + size = 8 // Offset, Flags + + stridx_size // Name + + GetCodedIndexSize (CodedIndex.Implementation); // Implementation + break; + case Table.NestedClass: + size = GetTableIndexSize (Table.TypeDef) // NestedClass + + GetTableIndexSize (Table.TypeDef); // EnclosingClass + break; + case Table.GenericParam: + size = 4 // Number, Flags + + GetCodedIndexSize (CodedIndex.TypeOrMethodDef) // Owner + + stridx_size; // Name + break; + case Table.MethodSpec: + size = GetCodedIndexSize (CodedIndex.MethodDefOrRef) // Method + + blobidx_size; // Instantiation + break; + case Table.GenericParamConstraint: + size = GetTableIndexSize (Table.GenericParam) // Owner + + GetCodedIndexSize (CodedIndex.TypeDefOrRef); // Constraint + break; + default: + throw new NotSupportedException (); + } + + int index = (int) table; + + tables [index].RowSize = (uint) size; + tables [index].Offset = offset; + + offset += (uint) size * tables [index].Length; + } + } + + public static Image ReadImageFrom (Stream stream) + { + try { + var reader = new ImageReader (stream); + reader.ReadImage (); + return reader.image; + } catch (EndOfStreamException e) { + throw new BadImageFormatException (stream.GetFullyQualifiedName (), e); + } + } + } +} diff --git a/Mono.Cecil.PE/ImageWriter.cs b/Mono.Cecil.PE/ImageWriter.cs new file mode 100644 index 000000000..939de6b95 --- /dev/null +++ b/Mono.Cecil.PE/ImageWriter.cs @@ -0,0 +1,820 @@ +// +// ImageWriter.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.IO; + +#if !READ_ONLY + +using Mono.Cecil.Cil; +using Mono.Cecil.Metadata; + +using RVA = System.UInt32; + +namespace Mono.Cecil.PE { + + sealed class ImageWriter : BinaryStreamWriter { + + readonly ModuleDefinition module; + readonly MetadataBuilder metadata; + readonly TextMap text_map; + + ImageDebugDirectory debug_directory; + byte [] debug_data; + + ByteBuffer win32_resources; + + const uint pe_header_size = 0x178u; + const uint section_header_size = 0x28u; + const uint file_alignment = 0x200; + const uint section_alignment = 0x2000; + const ulong image_base = 0x00400000; + + internal const RVA text_rva = 0x2000; + + readonly bool pe64; + readonly uint time_stamp; + + internal Section text; + internal Section rsrc; + internal Section reloc; + + ushort sections; + + ImageWriter (ModuleDefinition module, MetadataBuilder metadata, Stream stream) + : base (stream) + { + this.module = module; + this.metadata = metadata; + this.GetDebugHeader (); + this.GetWin32Resources (); + this.text_map = BuildTextMap (); + this.sections = 2; // text + reloc + this.pe64 = module.Architecture != TargetArchitecture.I386; + this.time_stamp = (uint) DateTime.UtcNow.Subtract (new DateTime (1970, 1, 1)).TotalSeconds; + } + + void GetDebugHeader () + { + var symbol_writer = metadata.symbol_writer; + if (symbol_writer == null) + return; + + if (!symbol_writer.GetDebugHeader (out debug_directory, out debug_data)) + debug_data = Empty.Array; + } + + void GetWin32Resources () + { + var rsrc = GetImageResourceSection (); + if (rsrc == null) + return; + + var raw_resources = new byte [rsrc.Data.Length]; + Buffer.BlockCopy (rsrc.Data, 0, raw_resources, 0, rsrc.Data.Length); + win32_resources = new ByteBuffer (raw_resources); + } + + Section GetImageResourceSection () + { + if (!module.HasImage) + return null; + + const string rsrc_section = ".rsrc"; + + return module.Image.GetSection (rsrc_section); + } + + public static ImageWriter CreateWriter (ModuleDefinition module, MetadataBuilder metadata, Stream stream) + { + var writer = new ImageWriter (module, metadata, stream); + writer.BuildSections (); + return writer; + } + + void BuildSections () + { + var has_win32_resources = win32_resources != null; + if (has_win32_resources) + sections++; + + text = CreateSection (".text", text_map.GetLength (), null); + var previous = text; + + if (has_win32_resources) { + rsrc = CreateSection (".rsrc", (uint) win32_resources.length, previous); + + PatchWin32Resources (win32_resources); + previous = rsrc; + } + + reloc = CreateSection (".reloc", 12u, previous); + } + + Section CreateSection (string name, uint size, Section previous) + { + return new Section { + Name = name, + VirtualAddress = previous != null + ? previous.VirtualAddress + Align (previous.VirtualSize, section_alignment) + : text_rva, + VirtualSize = size, + PointerToRawData = previous != null + ? previous.PointerToRawData + previous.SizeOfRawData + : Align (GetHeaderSize (), file_alignment), + SizeOfRawData = Align (size, file_alignment) + }; + } + + static uint Align (uint value, uint align) + { + align--; + return (value + align) & ~align; + } + + void WriteDOSHeader () + { + Write (new byte [] { + // dos header start + 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + // lfanew + 0x80, 0x00, 0x00, 0x00, + // dos header end + 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, + 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, + 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, + 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x20, 0x63, + 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x20, 0x62, + 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, + 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20, 0x6d, + 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a, + 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00 + }); + } + + void WritePEFileHeader () + { + WriteUInt32 (0x00004550); // Magic + WriteUInt16 (GetMachine ()); // Machine + WriteUInt16 (sections); // NumberOfSections + WriteUInt32 (time_stamp); + WriteUInt32 (0); // PointerToSymbolTable + WriteUInt32 (0); // NumberOfSymbols + WriteUInt16 ((ushort) (!pe64 ? 0xe0 : 0xf0)); // SizeOfOptionalHeader + + // ExecutableImage | (pe64 ? 32BitsMachine : LargeAddressAware) + var characteristics = (ushort) (0x0002 | (!pe64 ? 0x0100 : 0x0020)); + if (module.Kind == ModuleKind.Dll || module.Kind == ModuleKind.NetModule) + characteristics |= 0x2000; + WriteUInt16 (characteristics); // Characteristics + } + + ushort GetMachine () + { + switch (module.Architecture) { + case TargetArchitecture.I386: + return 0x014c; + case TargetArchitecture.AMD64: + return 0x8664; + case TargetArchitecture.IA64: + return 0x0200; + } + + throw new NotSupportedException (); + } + + void WriteOptionalHeaders () + { + WriteUInt16 ((ushort) (!pe64 ? 0x10b : 0x20b)); // Magic + WriteByte (8); // LMajor + WriteByte (0); // LMinor + WriteUInt32 (text.SizeOfRawData); // CodeSize + WriteUInt32 (reloc.SizeOfRawData + + (rsrc != null ? rsrc.SizeOfRawData : 0)); // InitializedDataSize + WriteUInt32 (0); // UninitializedDataSize + + var entry_point_rva = text_map.GetRVA (TextSegment.StartupStub); + if (module.Architecture == TargetArchitecture.IA64) + entry_point_rva += 0x20; + WriteUInt32 (entry_point_rva); // EntryPointRVA + WriteUInt32 (text_rva); // BaseOfCode + + if (!pe64) { + WriteUInt32 (0); // BaseOfData + WriteUInt32 ((uint) image_base); // ImageBase + } else { + WriteUInt64 (image_base); // ImageBase + } + + WriteUInt32 (section_alignment); // SectionAlignment + WriteUInt32 (file_alignment); // FileAlignment + + WriteUInt16 (4); // OSMajor + WriteUInt16 (0); // OSMinor + WriteUInt16 (0); // UserMajor + WriteUInt16 (0); // UserMinor + WriteUInt16 (4); // SubSysMajor + WriteUInt16 (0); // SubSysMinor + WriteUInt32 (0); // Reserved + + WriteUInt32 (reloc.VirtualAddress + Align (reloc.VirtualSize, section_alignment)); // ImageSize + WriteUInt32 (text.PointerToRawData); // HeaderSize + + WriteUInt32 (0); // Checksum + WriteUInt16 (GetSubSystem ()); // SubSystem + WriteUInt16 (0x8540); // DLLFlags + + const ulong stack_reserve = 0x100000; + const ulong stack_commit = 0x1000; + const ulong heap_reserve = 0x100000; + const ulong heap_commit = 0x1000; + + if (!pe64) { + WriteUInt32 ((uint) stack_reserve); + WriteUInt32 ((uint) stack_commit); + WriteUInt32 ((uint) heap_reserve); + WriteUInt32 ((uint) heap_commit); + } else { + WriteUInt64 (stack_reserve); + WriteUInt64 (stack_commit); + WriteUInt64 (heap_reserve); + WriteUInt64 (heap_commit); + } + + WriteUInt32 (0); // LoaderFlags + WriteUInt32 (16); // NumberOfDataDir + + WriteZeroDataDirectory (); // ExportTable + WriteDataDirectory (text_map.GetDataDirectory (TextSegment.ImportDirectory)); // ImportTable + if (rsrc != null) { // ResourceTable + WriteUInt32 (rsrc.VirtualAddress); + WriteUInt32 (rsrc.VirtualSize); + } else + WriteZeroDataDirectory (); + + WriteZeroDataDirectory (); // ExceptionTable + WriteZeroDataDirectory (); // CertificateTable + WriteUInt32 (reloc.VirtualAddress); // BaseRelocationTable + WriteUInt32 (reloc.VirtualSize); + + if (text_map.GetLength (TextSegment.DebugDirectory) > 0) { + WriteUInt32 (text_map.GetRVA (TextSegment.DebugDirectory)); + WriteUInt32 (28u); + } else + WriteZeroDataDirectory (); + + WriteZeroDataDirectory (); // Copyright + WriteZeroDataDirectory (); // GlobalPtr + WriteZeroDataDirectory (); // TLSTable + WriteZeroDataDirectory (); // LoadConfigTable + WriteZeroDataDirectory (); // BoundImport + WriteDataDirectory (text_map.GetDataDirectory (TextSegment.ImportAddressTable)); // IAT + WriteZeroDataDirectory (); // DelayImportDesc + WriteDataDirectory (text_map.GetDataDirectory (TextSegment.CLIHeader)); // CLIHeader + WriteZeroDataDirectory (); // Reserved + } + + void WriteZeroDataDirectory () + { + WriteUInt32 (0); + WriteUInt32 (0); + } + + ushort GetSubSystem () + { + switch (module.Kind) { + case ModuleKind.Console: + case ModuleKind.Dll: + case ModuleKind.NetModule: + return 0x3; + case ModuleKind.Windows: + return 0x2; + default: + throw new ArgumentOutOfRangeException (); + } + } + + void WriteSectionHeaders () + { + WriteSection (text, 0x60000020); + + if (rsrc != null) + WriteSection (rsrc, 0x40000040); + + WriteSection (reloc, 0x42000040); + } + + void WriteSection (Section section, uint characteristics) + { + var name = new byte [8]; + var sect_name = section.Name; + for (int i = 0; i < sect_name.Length; i++) + name [i] = (byte) sect_name [i]; + + WriteBytes (name); + WriteUInt32 (section.VirtualSize); + WriteUInt32 (section.VirtualAddress); + WriteUInt32 (section.SizeOfRawData); + WriteUInt32 (section.PointerToRawData); + WriteUInt32 (0); // PointerToRelocations + WriteUInt32 (0); // PointerToLineNumbers + WriteUInt16 (0); // NumberOfRelocations + WriteUInt16 (0); // NumberOfLineNumbers + WriteUInt32 (characteristics); + } + + void MoveTo (uint pointer) + { + BaseStream.Seek (pointer, SeekOrigin.Begin); + } + + void MoveToRVA (Section section, RVA rva) + { + BaseStream.Seek (section.PointerToRawData + rva - section.VirtualAddress, SeekOrigin.Begin); + } + + void MoveToRVA (TextSegment segment) + { + MoveToRVA (text, text_map.GetRVA (segment)); + } + + void WriteRVA (RVA rva) + { + if (!pe64) + WriteUInt32 (rva); + else + WriteUInt64 (rva); + } + + void WriteText () + { + MoveTo (text.PointerToRawData); + + // ImportAddressTable + + WriteRVA (text_map.GetRVA (TextSegment.ImportHintNameTable)); + WriteRVA (0); + + // CLIHeader + + WriteUInt32 (0x48); + WriteUInt16 (2); + WriteUInt16 ((ushort) ((module.Runtime <= TargetRuntime.Net_1_1) ? 0 : 5)); + + WriteUInt32 (text_map.GetRVA (TextSegment.MetadataHeader)); + WriteUInt32 (GetMetadataLength ()); + WriteUInt32 ((uint) module.Attributes); + WriteUInt32 (metadata.entry_point.ToUInt32 ()); + WriteDataDirectory (text_map.GetDataDirectory (TextSegment.Resources)); + WriteDataDirectory (text_map.GetDataDirectory (TextSegment.StrongNameSignature)); + WriteZeroDataDirectory (); // CodeManagerTable + WriteZeroDataDirectory (); // VTableFixups + WriteZeroDataDirectory (); // ExportAddressTableJumps + WriteZeroDataDirectory (); // ManagedNativeHeader + + // Code + + MoveToRVA (TextSegment.Code); + WriteBuffer (metadata.code); + + // Resources + + MoveToRVA (TextSegment.Resources); + WriteBuffer (metadata.resources); + + // Data + + if (metadata.data.length > 0) { + MoveToRVA (TextSegment.Data); + WriteBuffer (metadata.data); + } + + // StrongNameSignature + // stays blank + + // MetadataHeader + + MoveToRVA (TextSegment.MetadataHeader); + WriteMetadataHeader (); + + WriteMetadata (); + + // DebugDirectory + if (text_map.GetLength (TextSegment.DebugDirectory) > 0) { + MoveToRVA (TextSegment.DebugDirectory); + WriteDebugDirectory (); + } + + // ImportDirectory + MoveToRVA (TextSegment.ImportDirectory); + WriteImportDirectory (); + + // StartupStub + MoveToRVA (TextSegment.StartupStub); + WriteStartupStub (); + } + + uint GetMetadataLength () + { + return text_map.GetRVA (TextSegment.DebugDirectory) - text_map.GetRVA (TextSegment.MetadataHeader); + } + + void WriteMetadataHeader () + { + WriteUInt32 (0x424a5342); // Signature + WriteUInt16 (1); // MajorVersion + WriteUInt16 (1); // MinorVersion + WriteUInt32 (0); // Reserved + + var version = GetZeroTerminatedString (GetVersion ()); + WriteUInt32 ((uint) version.Length); + WriteBytes (version); + WriteUInt16 (0); // Flags + WriteUInt16 (GetStreamCount ()); + + uint offset = text_map.GetRVA (TextSegment.TableHeap) - text_map.GetRVA (TextSegment.MetadataHeader); + + WriteStreamHeader (ref offset, TextSegment.TableHeap, "#~"); + WriteStreamHeader (ref offset, TextSegment.StringHeap, "#Strings"); + WriteStreamHeader (ref offset, TextSegment.UserStringHeap, "#US"); + WriteStreamHeader (ref offset, TextSegment.GuidHeap, "#GUID"); + WriteStreamHeader (ref offset, TextSegment.BlobHeap, "#Blob"); + } + + string GetVersion () + { + switch (module.Runtime) { + case TargetRuntime.Net_1_0: + return "v1.0.3705"; + case TargetRuntime.Net_1_1: + return "v1.1.4322"; + case TargetRuntime.Net_2_0: + return "v2.0.50727"; + case TargetRuntime.Net_4_0: + default: + return "v4.0.30319"; + } + } + + ushort GetStreamCount () + { + return (ushort) ( + 1 // #~ + + 1 // #Strings + + (metadata.user_string_heap.IsEmpty ? 0 : 1) // #US + + 1 // GUID + + (metadata.blob_heap.IsEmpty ? 0 : 1)); // #Blob + } + + void WriteStreamHeader (ref uint offset, TextSegment heap, string name) + { + var length = (uint) text_map.GetLength (heap); + if (length == 0) + return; + + WriteUInt32 (offset); + WriteUInt32 (length); + WriteBytes (GetZeroTerminatedString (name)); + offset += length; + } + + static byte [] GetZeroTerminatedString (string @string) + { + return GetString (@string, (@string.Length + 1 + 3) & ~3); + } + + static byte [] GetSimpleString (string @string) + { + return GetString (@string, @string.Length); + } + + static byte [] GetString (string @string, int length) + { + var bytes = new byte [length]; + for (int i = 0; i < @string.Length; i++) + bytes [i] = (byte) @string [i]; + + return bytes; + } + + void WriteMetadata () + { + WriteHeap (TextSegment.TableHeap, metadata.table_heap); + WriteHeap (TextSegment.StringHeap, metadata.string_heap); + WriteHeap (TextSegment.UserStringHeap, metadata.user_string_heap); + WriteGuidHeap (); + WriteHeap (TextSegment.BlobHeap, metadata.blob_heap); + } + + void WriteHeap (TextSegment heap, HeapBuffer buffer) + { + if (buffer.IsEmpty) + return; + + MoveToRVA (heap); + WriteBuffer (buffer); + } + + void WriteGuidHeap () + { + MoveToRVA (TextSegment.GuidHeap); + WriteBytes (module.Mvid.ToByteArray ()); + } + + void WriteDebugDirectory () + { + WriteInt32 (debug_directory.Characteristics); + WriteUInt32 (time_stamp); + WriteInt16 (debug_directory.MajorVersion); + WriteInt16 (debug_directory.MinorVersion); + WriteInt32 (debug_directory.Type); + WriteInt32 (debug_directory.SizeOfData); + WriteInt32 (debug_directory.AddressOfRawData); + WriteInt32 ((int) BaseStream.Position + 4); + + WriteBytes (debug_data); + } + + void WriteImportDirectory () + { + WriteUInt32 (text_map.GetRVA (TextSegment.ImportDirectory) + 40); // ImportLookupTable + WriteUInt32 (0); // DateTimeStamp + WriteUInt32 (0); // ForwarderChain + WriteUInt32 (text_map.GetRVA (TextSegment.ImportHintNameTable) + 14); + WriteUInt32 (text_map.GetRVA (TextSegment.ImportAddressTable)); + Advance (20); + + // ImportLookupTable + WriteUInt32 (text_map.GetRVA (TextSegment.ImportHintNameTable)); + + // ImportHintNameTable + MoveToRVA (TextSegment.ImportHintNameTable); + + WriteUInt16 (0); // Hint + WriteBytes (GetRuntimeMain ()); + WriteByte (0); + WriteBytes (GetSimpleString ("mscoree.dll")); + WriteUInt16 (0); + } + + byte [] GetRuntimeMain () + { + return module.Kind == ModuleKind.Dll || module.Kind == ModuleKind.NetModule + ? GetSimpleString ("_CorDllMain") + : GetSimpleString ("_CorExeMain"); + } + + void WriteStartupStub () + { + switch (module.Architecture) { + case TargetArchitecture.I386: + WriteUInt16 (0x25ff); + WriteUInt32 ((uint) image_base + text_map.GetRVA (TextSegment.ImportAddressTable)); + return; + case TargetArchitecture.AMD64: + WriteUInt16 (0xa148); + WriteUInt32 ((uint) image_base + text_map.GetRVA (TextSegment.ImportAddressTable)); + WriteUInt16 (0xe0ff); + return; + case TargetArchitecture.IA64: + WriteBytes (new byte [] { + 0x0b, 0x48, 0x00, 0x02, 0x18, 0x10, 0xa0, 0x40, 0x24, 0x30, 0x28, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x10, 0x08, 0x00, 0x12, 0x18, 0x10, 0x60, 0x50, 0x04, 0x80, 0x03, 0x00, 0x60, 0x00, 0x80, 0x00 + }); + WriteUInt32 ((uint) image_base + text_map.GetRVA (TextSegment.StartupStub)); + WriteUInt32 ((uint) image_base + text_rva); + return; + } + } + + void WriteRsrc () + { + MoveTo (rsrc.PointerToRawData); + WriteBuffer (win32_resources); + } + + void WriteReloc () + { + MoveTo (reloc.PointerToRawData); + + var reloc_rva = text_map.GetRVA (TextSegment.StartupStub); + reloc_rva += module.Architecture == TargetArchitecture.IA64 ? 0x20u : 2; + var page_rva = reloc_rva & ~0xfffu; + + WriteUInt32 (page_rva); // PageRVA + WriteUInt32 (0x000c); // Block Size + + switch (module.Architecture) { + case TargetArchitecture.I386: + WriteUInt32 (0x3000 + reloc_rva - page_rva); + break; + case TargetArchitecture.AMD64: + WriteUInt32 (0xa000 + reloc_rva - page_rva); + break; + case TargetArchitecture.IA64: + WriteUInt16 ((ushort) (0xa000 + reloc_rva - page_rva)); + WriteUInt16 ((ushort) (0xa000 + reloc_rva - page_rva + 8)); + break; + } + + WriteBytes (new byte [file_alignment - reloc.VirtualSize]); + } + + public void WriteImage () + { + WriteDOSHeader (); + WritePEFileHeader (); + WriteOptionalHeaders (); + WriteSectionHeaders (); + WriteText (); + if (rsrc != null) + WriteRsrc (); + WriteReloc (); + } + + TextMap BuildTextMap () + { + var map = metadata.text_map; + + map.AddMap (TextSegment.Code, metadata.code.length, !pe64 ? 4 : 16); + map.AddMap (TextSegment.Resources, metadata.resources.length, 8); + map.AddMap (TextSegment.Data, metadata.data.length, 4); + if (metadata.data.length > 0) + metadata.table_heap.FixupData (map.GetRVA (TextSegment.Data)); + map.AddMap (TextSegment.StrongNameSignature, GetStrongNameLength (), 4); + + map.AddMap (TextSegment.MetadataHeader, GetMetadataHeaderLength ()); + map.AddMap (TextSegment.TableHeap, metadata.table_heap.length, 4); + map.AddMap (TextSegment.StringHeap, metadata.string_heap.length, 4); + map.AddMap (TextSegment.UserStringHeap, metadata.user_string_heap.IsEmpty ? 0 : metadata.user_string_heap.length, 4); + map.AddMap (TextSegment.GuidHeap, 16); + map.AddMap (TextSegment.BlobHeap, metadata.blob_heap.IsEmpty ? 0 : metadata.blob_heap.length, 4); + + int debug_dir_len = 0; + if (!debug_data.IsNullOrEmpty ()) { + const int debug_dir_header_len = 28; + + debug_directory.AddressOfRawData = (int) map.GetNextRVA (TextSegment.BlobHeap) + debug_dir_header_len; + debug_dir_len = debug_data.Length + debug_dir_header_len; + } + + map.AddMap (TextSegment.DebugDirectory, debug_dir_len, 4); + + RVA import_dir_rva = map.GetNextRVA (TextSegment.DebugDirectory); + RVA import_hnt_rva = import_dir_rva + (!pe64 ? 48u : 52u); + import_hnt_rva = (import_hnt_rva + 15u) & ~15u; + uint import_dir_len = (import_hnt_rva - import_dir_rva) + 27u; + + RVA startup_stub_rva = import_dir_rva + import_dir_len; + startup_stub_rva = module.Architecture == TargetArchitecture.IA64 + ? (startup_stub_rva + 15u) & ~15u + : 2 + ((startup_stub_rva + 3u) & ~3u); + + map.AddMap (TextSegment.ImportDirectory, new Range (import_dir_rva, import_dir_len)); + map.AddMap (TextSegment.ImportHintNameTable, new Range (import_hnt_rva, 0)); + map.AddMap (TextSegment.StartupStub, new Range (startup_stub_rva, GetStartupStubLength ())); + + return map; + } + + uint GetStartupStubLength () + { + switch (module.Architecture) { + case TargetArchitecture.I386: + return 6; + case TargetArchitecture.AMD64: + return 12; + case TargetArchitecture.IA64: + return 48; + default: + throw new InvalidOperationException (); + } + } + + int GetMetadataHeaderLength () + { + return + // MetadataHeader + 40 + // #~ header + + 12 + // #Strings header + + 20 + // #US header + + (metadata.user_string_heap.IsEmpty ? 0 : 12) + // #GUID header + + 16 + // #Blob header + + (metadata.blob_heap.IsEmpty ? 0 : 16); + } + + int GetStrongNameLength () + { + if ((module.Attributes & ModuleAttributes.StrongNameSigned) == 0) + return 0; + + if (module.Assembly == null) + throw new InvalidOperationException (); + + var public_key = module.Assembly.Name.PublicKey; + + if (public_key != null) { + // in fx 2.0 the key may be from 384 to 16384 bits + // so we must calculate the signature size based on + // the size of the public key (minus the 32 byte header) + int size = public_key.Length; + if (size > 32) + return size - 32; + // note: size == 16 for the ECMA "key" which is replaced + // by the runtime with a 1024 bits key (128 bytes) + } + + return 128; // default strongname signature size + } + + public DataDirectory GetStrongNameSignatureDirectory () + { + return text_map.GetDataDirectory (TextSegment.StrongNameSignature); + } + + public uint GetHeaderSize () + { + return pe_header_size + (sections * section_header_size); + } + + void PatchWin32Resources (ByteBuffer resources) + { + PatchResourceDirectoryTable (resources); + } + + void PatchResourceDirectoryTable (ByteBuffer resources) + { + resources.Advance (12); + + var entries = resources.ReadUInt16 () + resources.ReadUInt16 (); + + for (int i = 0; i < entries; i++) + PatchResourceDirectoryEntry (resources); + } + + void PatchResourceDirectoryEntry (ByteBuffer resources) + { + resources.Advance (4); + var child = resources.ReadUInt32 (); + + var position = resources.position; + resources.position = (int) child & 0x7fffffff; + + if ((child & 0x80000000) != 0) + PatchResourceDirectoryTable (resources); + else + PatchResourceDataEntry (resources); + + resources.position = position; + } + + void PatchResourceDataEntry (ByteBuffer resources) + { + var old_rsrc = GetImageResourceSection (); + var rva = resources.ReadUInt32 (); + resources.position -= 4; + resources.WriteUInt32 (rva - old_rsrc.VirtualAddress + rsrc.VirtualAddress); + } + } +} + +#endif diff --git a/Mono.Cecil.PE/Section.cs b/Mono.Cecil.PE/Section.cs new file mode 100644 index 000000000..54935f989 --- /dev/null +++ b/Mono.Cecil.PE/Section.cs @@ -0,0 +1,43 @@ +// +// Section.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +using RVA = System.UInt32; + +namespace Mono.Cecil.PE { + + sealed class Section { + public string Name; + public RVA VirtualAddress; + public uint VirtualSize; + public uint SizeOfRawData; + public uint PointerToRawData; + public byte [] Data; + } +} diff --git a/Mono.Cecil.PE/TextMap.cs b/Mono.Cecil.PE/TextMap.cs new file mode 100644 index 000000000..daeda0cff --- /dev/null +++ b/Mono.Cecil.PE/TextMap.cs @@ -0,0 +1,129 @@ +// +// TextMap.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +#if !READ_ONLY + +using RVA = System.UInt32; + +namespace Mono.Cecil.PE { + + enum TextSegment { + ImportAddressTable, + CLIHeader, + Code, + Resources, + Data, + StrongNameSignature, + + // Metadata + MetadataHeader, + TableHeap, + StringHeap, + UserStringHeap, + GuidHeap, + BlobHeap, + // End Metadata + + DebugDirectory, + ImportDirectory, + ImportHintNameTable, + StartupStub, + } + + sealed class TextMap { + + readonly Range [] map = new Range [16 /*Enum.GetValues (typeof (TextSegment)).Length*/]; + + public void AddMap (TextSegment segment, int length) + { + map [(int) segment] = new Range (GetStart (segment), (uint) length); + } + + public void AddMap (TextSegment segment, int length, int align) + { + align--; + + AddMap (segment, (length + align) & ~align); + } + + public void AddMap (TextSegment segment, Range range) + { + map [(int) segment] = range; + } + + public Range GetRange (TextSegment segment) + { + return map [(int) segment]; + } + + public DataDirectory GetDataDirectory (TextSegment segment) + { + var range = map [(int) segment]; + + return new DataDirectory (range.Length == 0 ? 0 : range.Start, range.Length); + } + + public RVA GetRVA (TextSegment segment) + { + return map [(int) segment].Start; + } + + public RVA GetNextRVA (TextSegment segment) + { + var i = (int) segment; + return map [i].Start + map [i].Length; + } + + public int GetLength (TextSegment segment) + { + return (int) map [(int) segment].Length; + } + + RVA GetStart (TextSegment segment) + { + var index = (int) segment; + return index == 0 ? ImageWriter.text_rva : ComputeStart (index); + } + + RVA ComputeStart (int index) + { + index--; + return map [index].Start + map [index].Length; + } + + public uint GetLength () + { + var range = map [(int) TextSegment.StartupStub]; + return range.Start - ImageWriter.text_rva + range.Length; + } + } +} + +#endif diff --git a/Mono.Cecil.csproj b/Mono.Cecil.csproj new file mode 100644 index 000000000..3a237c11b --- /dev/null +++ b/Mono.Cecil.csproj @@ -0,0 +1,264 @@ + + + + net_4_0_Debug + AnyCPU + 9.0.30729 + 2.0 + {D68133BD-1E63-496E-9EDE-4FBDBF77B486} + Library + Properties + Mono.Cecil + Mono.Cecil + 512 + true + mono.snk + + + true + full + false + bin\net_2_0_Debug\ + DEBUG;TRACE + prompt + 4 + v2.0 + + + pdbonly + true + bin\net_2_0_Release\ + TRACE + prompt + 4 + v2.0 + + + true + full + false + bin\net_3_5_Debug\ + DEBUG;TRACE;NET_3_5 + prompt + 4 + v3.5 + + + pdbonly + true + bin\net_3_5_Release\ + TRACE;NET_3_5 + prompt + 4 + v3.5 + + + true + full + false + bin\net_4_0_Debug\ + DEBUG;TRACE;NET_3_5;NET_4_0 + prompt + 4 + v4.0 + + + pdbonly + true + bin\net_4_0_Release\ + TRACE;NET_3_5;NET_4_0 + prompt + 4 + v4.0 + + + true + full + false + bin\silverlight_Debug\ + DEBUG;TRACE;NET_3_5;NET_4_0;SILVERLIGHT + prompt + 4 + Silverlight + v4.0 + + + pdbonly + true + bin\silverlight_Release\ + TRACE;NET_3_5;NET_4_0;SILVERLIGHT + prompt + 4 + Silverlight + v4.0 + + + true + full + false + bin\winphone_Debug\ + DEBUG;TRACE;NET_3_5;NET_4_0;SILVERLIGHT;CF + prompt + 4 + WindowsPhone + Silverlight + v4.0 + + + pdbonly + true + bin\winphone_Release\ + TRACE;NET_3_5;NET_4_0;SILVERLIGHT;CF + prompt + 4 + WindowsPhone + Silverlight + v4.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Mono.Cecil.nunit b/Mono.Cecil.nunit new file mode 100755 index 000000000..1cb0ebab1 --- /dev/null +++ b/Mono.Cecil.nunit @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/Mono.Cecil.sln b/Mono.Cecil.sln new file mode 100644 index 000000000..7f2eda7f9 --- /dev/null +++ b/Mono.Cecil.sln @@ -0,0 +1,197 @@ +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{74E5ECE0-06B4-401C-AEBA-E8DD53E17943}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Symbols", "Symbols", "{929D5B3B-E29A-40CC-93D8-0FF43A6F9FA1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Cecil", "Mono.Cecil.csproj", "{D68133BD-1E63-496E-9EDE-4FBDBF77B486}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Cecil.Tests", "Test\Mono.Cecil.Tests.csproj", "{A47B1F49-A81A-43E8-BE6B-DD28AF2C4055}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "dbg", "dbg\dbg.csproj", "{89A775F3-64AB-485E-B958-60C25254B732}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Cecil.Mdb", "symbols\mdb\Mono.Cecil.Mdb.csproj", "{8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Cecil.Mdb.Tests", "symbols\mdb\Test\Mono.Cecil.Mdb.Tests.csproj", "{AC71DF9C-99FA-4A63-990A-66C8010355A6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Cecil.Pdb", "symbols\pdb\Mono.Cecil.Pdb.csproj", "{63E6915C-7EA4-4D76-AB28-0D7191EEA626}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Cecil.Pdb.Tests", "symbols\pdb\Test\Mono.Cecil.Pdb.Tests.csproj", "{29300103-CB76-4A1D-B6FD-FFD91C1EC8AA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Cecil.Rocks.Tests", "rocks\Test\Mono.Cecil.Rocks.Tests.csproj", "{C6CFD7E1-B855-44DC-B4CE-9CD72984AF52}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Cecil.Rocks", "rocks\Mono.Cecil.Rocks.csproj", "{FBC6DD59-D09D-499C-B03C-99C1C78FF2AC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + net_2_0_Debug|Any CPU = net_2_0_Debug|Any CPU + net_2_0_Release|Any CPU = net_2_0_Release|Any CPU + net_3_5_Debug|Any CPU = net_3_5_Debug|Any CPU + net_3_5_Release|Any CPU = net_3_5_Release|Any CPU + net_4_0_Debug|Any CPU = net_4_0_Debug|Any CPU + net_4_0_Release|Any CPU = net_4_0_Release|Any CPU + silverlight_Debug|Any CPU = silverlight_Debug|Any CPU + silverlight_Release|Any CPU = silverlight_Release|Any CPU + winphone_Debug|Any CPU = winphone_Debug|Any CPU + winphone_Release|Any CPU = winphone_Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_2_0_Debug|Any CPU.ActiveCfg = net_2_0_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_2_0_Debug|Any CPU.Build.0 = net_2_0_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_2_0_Release|Any CPU.ActiveCfg = net_2_0_Release|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_2_0_Release|Any CPU.Build.0 = net_2_0_Release|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_3_5_Debug|Any CPU.ActiveCfg = net_3_5_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_3_5_Debug|Any CPU.Build.0 = net_3_5_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_3_5_Release|Any CPU.ActiveCfg = net_3_5_Release|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_3_5_Release|Any CPU.Build.0 = net_3_5_Release|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_4_0_Debug|Any CPU.ActiveCfg = net_4_0_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_4_0_Debug|Any CPU.Build.0 = net_4_0_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_4_0_Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_4_0_Release|Any CPU.Build.0 = net_4_0_Release|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.silverlight_Debug|Any CPU.ActiveCfg = silverlight_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.silverlight_Debug|Any CPU.Build.0 = silverlight_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.silverlight_Release|Any CPU.ActiveCfg = silverlight_Release|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.silverlight_Release|Any CPU.Build.0 = silverlight_Release|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.winphone_Debug|Any CPU.ActiveCfg = winphone_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.winphone_Debug|Any CPU.Build.0 = winphone_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.winphone_Release|Any CPU.ActiveCfg = winphone_Release|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.winphone_Release|Any CPU.Build.0 = winphone_Release|Any CPU + {A47B1F49-A81A-43E8-BE6B-DD28AF2C4055}.net_2_0_Debug|Any CPU.ActiveCfg = net_2_0_Debug|Any CPU + {A47B1F49-A81A-43E8-BE6B-DD28AF2C4055}.net_2_0_Debug|Any CPU.Build.0 = net_2_0_Debug|Any CPU + {A47B1F49-A81A-43E8-BE6B-DD28AF2C4055}.net_2_0_Release|Any CPU.ActiveCfg = net_2_0_Release|Any CPU + {A47B1F49-A81A-43E8-BE6B-DD28AF2C4055}.net_2_0_Release|Any CPU.Build.0 = net_2_0_Release|Any CPU + {A47B1F49-A81A-43E8-BE6B-DD28AF2C4055}.net_3_5_Debug|Any CPU.ActiveCfg = net_3_5_Debug|Any CPU + {A47B1F49-A81A-43E8-BE6B-DD28AF2C4055}.net_3_5_Debug|Any CPU.Build.0 = net_3_5_Debug|Any CPU + {A47B1F49-A81A-43E8-BE6B-DD28AF2C4055}.net_3_5_Release|Any CPU.ActiveCfg = net_3_5_Release|Any CPU + {A47B1F49-A81A-43E8-BE6B-DD28AF2C4055}.net_3_5_Release|Any CPU.Build.0 = net_3_5_Release|Any CPU + {A47B1F49-A81A-43E8-BE6B-DD28AF2C4055}.net_4_0_Debug|Any CPU.ActiveCfg = net_4_0_Debug|Any CPU + {A47B1F49-A81A-43E8-BE6B-DD28AF2C4055}.net_4_0_Debug|Any CPU.Build.0 = net_4_0_Debug|Any CPU + {A47B1F49-A81A-43E8-BE6B-DD28AF2C4055}.net_4_0_Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {A47B1F49-A81A-43E8-BE6B-DD28AF2C4055}.net_4_0_Release|Any CPU.Build.0 = net_4_0_Release|Any CPU + {A47B1F49-A81A-43E8-BE6B-DD28AF2C4055}.silverlight_Debug|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {A47B1F49-A81A-43E8-BE6B-DD28AF2C4055}.silverlight_Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {A47B1F49-A81A-43E8-BE6B-DD28AF2C4055}.winphone_Debug|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {A47B1F49-A81A-43E8-BE6B-DD28AF2C4055}.winphone_Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {89A775F3-64AB-485E-B958-60C25254B732}.net_2_0_Debug|Any CPU.ActiveCfg = net_4_0_Debug|Any CPU + {89A775F3-64AB-485E-B958-60C25254B732}.net_2_0_Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {89A775F3-64AB-485E-B958-60C25254B732}.net_3_5_Debug|Any CPU.ActiveCfg = net_3_5_Debug|Any CPU + {89A775F3-64AB-485E-B958-60C25254B732}.net_3_5_Debug|Any CPU.Build.0 = net_3_5_Debug|Any CPU + {89A775F3-64AB-485E-B958-60C25254B732}.net_3_5_Release|Any CPU.ActiveCfg = net_3_5_Release|Any CPU + {89A775F3-64AB-485E-B958-60C25254B732}.net_3_5_Release|Any CPU.Build.0 = net_3_5_Release|Any CPU + {89A775F3-64AB-485E-B958-60C25254B732}.net_4_0_Debug|Any CPU.ActiveCfg = net_4_0_Debug|Any CPU + {89A775F3-64AB-485E-B958-60C25254B732}.net_4_0_Debug|Any CPU.Build.0 = net_4_0_Debug|Any CPU + {89A775F3-64AB-485E-B958-60C25254B732}.net_4_0_Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {89A775F3-64AB-485E-B958-60C25254B732}.net_4_0_Release|Any CPU.Build.0 = net_4_0_Release|Any CPU + {89A775F3-64AB-485E-B958-60C25254B732}.silverlight_Debug|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {89A775F3-64AB-485E-B958-60C25254B732}.silverlight_Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {89A775F3-64AB-485E-B958-60C25254B732}.winphone_Debug|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {89A775F3-64AB-485E-B958-60C25254B732}.winphone_Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_2_0_Debug|Any CPU.ActiveCfg = net_2_0_Debug|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_2_0_Debug|Any CPU.Build.0 = net_2_0_Debug|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_2_0_Release|Any CPU.ActiveCfg = net_2_0_Release|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_2_0_Release|Any CPU.Build.0 = net_2_0_Release|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_3_5_Debug|Any CPU.ActiveCfg = net_3_5_Debug|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_3_5_Debug|Any CPU.Build.0 = net_3_5_Debug|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_3_5_Release|Any CPU.ActiveCfg = net_3_5_Release|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_3_5_Release|Any CPU.Build.0 = net_3_5_Release|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_4_0_Debug|Any CPU.ActiveCfg = net_4_0_Debug|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_4_0_Debug|Any CPU.Build.0 = net_4_0_Debug|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_4_0_Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_4_0_Release|Any CPU.Build.0 = net_4_0_Release|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.silverlight_Debug|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.silverlight_Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.winphone_Debug|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.winphone_Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {AC71DF9C-99FA-4A63-990A-66C8010355A6}.net_2_0_Debug|Any CPU.ActiveCfg = net_2_0_Debug|Any CPU + {AC71DF9C-99FA-4A63-990A-66C8010355A6}.net_2_0_Debug|Any CPU.Build.0 = net_2_0_Debug|Any CPU + {AC71DF9C-99FA-4A63-990A-66C8010355A6}.net_2_0_Release|Any CPU.ActiveCfg = net_2_0_Release|Any CPU + {AC71DF9C-99FA-4A63-990A-66C8010355A6}.net_2_0_Release|Any CPU.Build.0 = net_2_0_Release|Any CPU + {AC71DF9C-99FA-4A63-990A-66C8010355A6}.net_3_5_Debug|Any CPU.ActiveCfg = net_3_5_Debug|Any CPU + {AC71DF9C-99FA-4A63-990A-66C8010355A6}.net_3_5_Debug|Any CPU.Build.0 = net_3_5_Debug|Any CPU + {AC71DF9C-99FA-4A63-990A-66C8010355A6}.net_3_5_Release|Any CPU.ActiveCfg = net_3_5_Release|Any CPU + {AC71DF9C-99FA-4A63-990A-66C8010355A6}.net_3_5_Release|Any CPU.Build.0 = net_3_5_Release|Any CPU + {AC71DF9C-99FA-4A63-990A-66C8010355A6}.net_4_0_Debug|Any CPU.ActiveCfg = net_4_0_Debug|Any CPU + {AC71DF9C-99FA-4A63-990A-66C8010355A6}.net_4_0_Debug|Any CPU.Build.0 = net_4_0_Debug|Any CPU + {AC71DF9C-99FA-4A63-990A-66C8010355A6}.net_4_0_Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {AC71DF9C-99FA-4A63-990A-66C8010355A6}.net_4_0_Release|Any CPU.Build.0 = net_4_0_Release|Any CPU + {AC71DF9C-99FA-4A63-990A-66C8010355A6}.silverlight_Debug|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {AC71DF9C-99FA-4A63-990A-66C8010355A6}.silverlight_Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {AC71DF9C-99FA-4A63-990A-66C8010355A6}.winphone_Debug|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {AC71DF9C-99FA-4A63-990A-66C8010355A6}.winphone_Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {63E6915C-7EA4-4D76-AB28-0D7191EEA626}.net_2_0_Debug|Any CPU.ActiveCfg = net_2_0_Debug|Any CPU + {63E6915C-7EA4-4D76-AB28-0D7191EEA626}.net_2_0_Debug|Any CPU.Build.0 = net_2_0_Debug|Any CPU + {63E6915C-7EA4-4D76-AB28-0D7191EEA626}.net_2_0_Release|Any CPU.ActiveCfg = net_2_0_Release|Any CPU + {63E6915C-7EA4-4D76-AB28-0D7191EEA626}.net_2_0_Release|Any CPU.Build.0 = net_2_0_Release|Any CPU + {63E6915C-7EA4-4D76-AB28-0D7191EEA626}.net_3_5_Debug|Any CPU.ActiveCfg = net_3_5_Debug|Any CPU + {63E6915C-7EA4-4D76-AB28-0D7191EEA626}.net_3_5_Debug|Any CPU.Build.0 = net_3_5_Debug|Any CPU + {63E6915C-7EA4-4D76-AB28-0D7191EEA626}.net_3_5_Release|Any CPU.ActiveCfg = net_3_5_Release|Any CPU + {63E6915C-7EA4-4D76-AB28-0D7191EEA626}.net_3_5_Release|Any CPU.Build.0 = net_3_5_Release|Any CPU + {63E6915C-7EA4-4D76-AB28-0D7191EEA626}.net_4_0_Debug|Any CPU.ActiveCfg = net_4_0_Debug|Any CPU + {63E6915C-7EA4-4D76-AB28-0D7191EEA626}.net_4_0_Debug|Any CPU.Build.0 = net_4_0_Debug|Any CPU + {63E6915C-7EA4-4D76-AB28-0D7191EEA626}.net_4_0_Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {63E6915C-7EA4-4D76-AB28-0D7191EEA626}.net_4_0_Release|Any CPU.Build.0 = net_4_0_Release|Any CPU + {63E6915C-7EA4-4D76-AB28-0D7191EEA626}.silverlight_Debug|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {63E6915C-7EA4-4D76-AB28-0D7191EEA626}.silverlight_Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {63E6915C-7EA4-4D76-AB28-0D7191EEA626}.winphone_Debug|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {63E6915C-7EA4-4D76-AB28-0D7191EEA626}.winphone_Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {29300103-CB76-4A1D-B6FD-FFD91C1EC8AA}.net_2_0_Debug|Any CPU.ActiveCfg = net_2_0_Debug|Any CPU + {29300103-CB76-4A1D-B6FD-FFD91C1EC8AA}.net_2_0_Debug|Any CPU.Build.0 = net_2_0_Debug|Any CPU + {29300103-CB76-4A1D-B6FD-FFD91C1EC8AA}.net_2_0_Release|Any CPU.ActiveCfg = net_2_0_Release|Any CPU + {29300103-CB76-4A1D-B6FD-FFD91C1EC8AA}.net_2_0_Release|Any CPU.Build.0 = net_2_0_Release|Any CPU + {29300103-CB76-4A1D-B6FD-FFD91C1EC8AA}.net_3_5_Debug|Any CPU.ActiveCfg = net_3_5_Debug|Any CPU + {29300103-CB76-4A1D-B6FD-FFD91C1EC8AA}.net_3_5_Debug|Any CPU.Build.0 = net_3_5_Debug|Any CPU + {29300103-CB76-4A1D-B6FD-FFD91C1EC8AA}.net_3_5_Release|Any CPU.ActiveCfg = net_3_5_Release|Any CPU + {29300103-CB76-4A1D-B6FD-FFD91C1EC8AA}.net_3_5_Release|Any CPU.Build.0 = net_3_5_Release|Any CPU + {29300103-CB76-4A1D-B6FD-FFD91C1EC8AA}.net_4_0_Debug|Any CPU.ActiveCfg = net_4_0_Debug|Any CPU + {29300103-CB76-4A1D-B6FD-FFD91C1EC8AA}.net_4_0_Debug|Any CPU.Build.0 = net_4_0_Debug|Any CPU + {29300103-CB76-4A1D-B6FD-FFD91C1EC8AA}.net_4_0_Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {29300103-CB76-4A1D-B6FD-FFD91C1EC8AA}.net_4_0_Release|Any CPU.Build.0 = net_4_0_Release|Any CPU + {29300103-CB76-4A1D-B6FD-FFD91C1EC8AA}.silverlight_Debug|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {29300103-CB76-4A1D-B6FD-FFD91C1EC8AA}.silverlight_Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {29300103-CB76-4A1D-B6FD-FFD91C1EC8AA}.winphone_Debug|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {29300103-CB76-4A1D-B6FD-FFD91C1EC8AA}.winphone_Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {C6CFD7E1-B855-44DC-B4CE-9CD72984AF52}.net_2_0_Debug|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {C6CFD7E1-B855-44DC-B4CE-9CD72984AF52}.net_2_0_Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {C6CFD7E1-B855-44DC-B4CE-9CD72984AF52}.net_3_5_Debug|Any CPU.ActiveCfg = net_3_5_Debug|Any CPU + {C6CFD7E1-B855-44DC-B4CE-9CD72984AF52}.net_3_5_Debug|Any CPU.Build.0 = net_3_5_Debug|Any CPU + {C6CFD7E1-B855-44DC-B4CE-9CD72984AF52}.net_3_5_Release|Any CPU.ActiveCfg = net_3_5_Release|Any CPU + {C6CFD7E1-B855-44DC-B4CE-9CD72984AF52}.net_3_5_Release|Any CPU.Build.0 = net_3_5_Release|Any CPU + {C6CFD7E1-B855-44DC-B4CE-9CD72984AF52}.net_4_0_Debug|Any CPU.ActiveCfg = net_4_0_Debug|Any CPU + {C6CFD7E1-B855-44DC-B4CE-9CD72984AF52}.net_4_0_Debug|Any CPU.Build.0 = net_4_0_Debug|Any CPU + {C6CFD7E1-B855-44DC-B4CE-9CD72984AF52}.net_4_0_Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {C6CFD7E1-B855-44DC-B4CE-9CD72984AF52}.net_4_0_Release|Any CPU.Build.0 = net_4_0_Release|Any CPU + {C6CFD7E1-B855-44DC-B4CE-9CD72984AF52}.silverlight_Debug|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {C6CFD7E1-B855-44DC-B4CE-9CD72984AF52}.silverlight_Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {C6CFD7E1-B855-44DC-B4CE-9CD72984AF52}.winphone_Debug|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {C6CFD7E1-B855-44DC-B4CE-9CD72984AF52}.winphone_Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {FBC6DD59-D09D-499C-B03C-99C1C78FF2AC}.net_2_0_Debug|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {FBC6DD59-D09D-499C-B03C-99C1C78FF2AC}.net_2_0_Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {FBC6DD59-D09D-499C-B03C-99C1C78FF2AC}.net_3_5_Debug|Any CPU.ActiveCfg = net_3_5_Debug|Any CPU + {FBC6DD59-D09D-499C-B03C-99C1C78FF2AC}.net_3_5_Debug|Any CPU.Build.0 = net_3_5_Debug|Any CPU + {FBC6DD59-D09D-499C-B03C-99C1C78FF2AC}.net_3_5_Release|Any CPU.ActiveCfg = net_3_5_Release|Any CPU + {FBC6DD59-D09D-499C-B03C-99C1C78FF2AC}.net_3_5_Release|Any CPU.Build.0 = net_3_5_Release|Any CPU + {FBC6DD59-D09D-499C-B03C-99C1C78FF2AC}.net_4_0_Debug|Any CPU.ActiveCfg = net_4_0_Debug|Any CPU + {FBC6DD59-D09D-499C-B03C-99C1C78FF2AC}.net_4_0_Debug|Any CPU.Build.0 = net_4_0_Debug|Any CPU + {FBC6DD59-D09D-499C-B03C-99C1C78FF2AC}.net_4_0_Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {FBC6DD59-D09D-499C-B03C-99C1C78FF2AC}.net_4_0_Release|Any CPU.Build.0 = net_4_0_Release|Any CPU + {FBC6DD59-D09D-499C-B03C-99C1C78FF2AC}.silverlight_Debug|Any CPU.ActiveCfg = silverlight_Debug|Any CPU + {FBC6DD59-D09D-499C-B03C-99C1C78FF2AC}.silverlight_Debug|Any CPU.Build.0 = silverlight_Debug|Any CPU + {FBC6DD59-D09D-499C-B03C-99C1C78FF2AC}.silverlight_Release|Any CPU.ActiveCfg = silverlight_Release|Any CPU + {FBC6DD59-D09D-499C-B03C-99C1C78FF2AC}.silverlight_Release|Any CPU.Build.0 = silverlight_Release|Any CPU + {FBC6DD59-D09D-499C-B03C-99C1C78FF2AC}.winphone_Debug|Any CPU.ActiveCfg = winphone_Debug|Any CPU + {FBC6DD59-D09D-499C-B03C-99C1C78FF2AC}.winphone_Debug|Any CPU.Build.0 = winphone_Debug|Any CPU + {FBC6DD59-D09D-499C-B03C-99C1C78FF2AC}.winphone_Release|Any CPU.ActiveCfg = winphone_Release|Any CPU + {FBC6DD59-D09D-499C-B03C-99C1C78FF2AC}.winphone_Release|Any CPU.Build.0 = winphone_Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {A47B1F49-A81A-43E8-BE6B-DD28AF2C4055} = {74E5ECE0-06B4-401C-AEBA-E8DD53E17943} + {AC71DF9C-99FA-4A63-990A-66C8010355A6} = {74E5ECE0-06B4-401C-AEBA-E8DD53E17943} + {29300103-CB76-4A1D-B6FD-FFD91C1EC8AA} = {74E5ECE0-06B4-401C-AEBA-E8DD53E17943} + {C6CFD7E1-B855-44DC-B4CE-9CD72984AF52} = {74E5ECE0-06B4-401C-AEBA-E8DD53E17943} + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD} = {929D5B3B-E29A-40CC-93D8-0FF43A6F9FA1} + {63E6915C-7EA4-4D76-AB28-0D7191EEA626} = {929D5B3B-E29A-40CC-93D8-0FF43A6F9FA1} + EndGlobalSection +EndGlobal diff --git a/Mono.Cecil/ArrayType.cs b/Mono.Cecil/ArrayType.cs new file mode 100644 index 000000000..e3a060f7b --- /dev/null +++ b/Mono.Cecil/ArrayType.cs @@ -0,0 +1,159 @@ +// +// ArrayType.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Text; +using Mono.Collections.Generic; +using MD = Mono.Cecil.Metadata; + +namespace Mono.Cecil { + + public struct ArrayDimension { + + int? lower_bound; + int? upper_bound; + + public int? LowerBound { + get { return lower_bound; } + set { lower_bound = value; } + } + + public int? UpperBound { + get { return upper_bound; } + set { upper_bound = value; } + } + + public bool IsSized { + get { return lower_bound.HasValue || upper_bound.HasValue; } + } + + public ArrayDimension (int? lowerBound, int? upperBound) + { + this.lower_bound = lowerBound; + this.upper_bound = upperBound; + } + + public override string ToString () + { + return !IsSized + ? string.Empty + : lower_bound + "..." + upper_bound; + } + } + + public sealed class ArrayType : TypeSpecification { + + Collection dimensions; + + public Collection Dimensions { + get { + if (dimensions != null) + return dimensions; + + dimensions = new Collection (); + dimensions.Add (new ArrayDimension ()); + return dimensions; + } + } + + public int Rank { + get { return dimensions == null ? 1 : dimensions.Count; } + } + + public bool IsVector { + get { + if (dimensions == null) + return true; + + if (dimensions.Count > 1) + return false; + + var dimension = dimensions [0]; + + return !dimension.IsSized; + } + } + + public override bool IsValueType { + get { return false; } + set { throw new InvalidOperationException (); } + } + + public override string Name { + get { return base.Name + Suffix; } + } + + public override string FullName { + get { return base.FullName + Suffix; } + } + + string Suffix { + get { + if (IsVector) + return "[]"; + + var suffix = new StringBuilder (); + suffix.Append ("["); + for (int i = 0; i < dimensions.Count; i++) { + if (i > 0) + suffix.Append (","); + + suffix.Append (dimensions [i].ToString ()); + } + suffix.Append ("]"); + + return suffix.ToString (); + } + } + + public override bool IsArray { + get { return true; } + } + + public ArrayType (TypeReference type) + : base (type) + { + Mixin.CheckType (type); + this.etype = MD.ElementType.Array; + } + + public ArrayType (TypeReference type, int rank) + : this (type) + { + Mixin.CheckType (type); + + if (rank == 1) + return; + + dimensions = new Collection (rank); + for (int i = 0; i < rank; i++) + dimensions.Add (new ArrayDimension ()); + this.etype = MD.ElementType.Array; + } + } +} diff --git a/Mono.Cecil/AssemblyDefinition.cs b/Mono.Cecil/AssemblyDefinition.cs new file mode 100644 index 000000000..bb757d38c --- /dev/null +++ b/Mono.Cecil/AssemblyDefinition.cs @@ -0,0 +1,189 @@ +// +// AssemblyDefinition.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.IO; + +using Mono.Collections.Generic; + +namespace Mono.Cecil { + + public sealed class AssemblyDefinition : ICustomAttributeProvider, ISecurityDeclarationProvider { + + AssemblyNameDefinition name; + + internal ModuleDefinition main_module; + Collection modules; + Collection custom_attributes; + Collection security_declarations; + + public AssemblyNameDefinition Name { + get { return name; } + set { name = value; } + } + + public string FullName { + get { return name != null ? name.FullName : string.Empty; } + } + + public MetadataToken MetadataToken { + get { return new MetadataToken (TokenType.Assembly, 1); } + set { } + } + + public Collection Modules { + get { + if (modules != null) + return modules; + + if (main_module.HasImage) + return modules = main_module.Read (this, (_, reader) => reader.ReadModules ()); + + return modules = new Collection { main_module }; + } + } + + public ModuleDefinition MainModule { + get { return main_module; } + } + + public MethodDefinition EntryPoint { + get { return main_module.EntryPoint; } + set { main_module.EntryPoint = value; } + } + + public bool HasCustomAttributes { + get { + if (custom_attributes != null) + return custom_attributes.Count > 0; + + return this.GetHasCustomAttributes (main_module); + } + } + + public Collection CustomAttributes { + get { return custom_attributes ?? (custom_attributes = this.GetCustomAttributes (main_module)); } + } + + public bool HasSecurityDeclarations { + get { + if (security_declarations != null) + return security_declarations.Count > 0; + + return this.GetHasSecurityDeclarations (main_module); + } + } + + public Collection SecurityDeclarations { + get { return security_declarations ?? (security_declarations = this.GetSecurityDeclarations (main_module)); } + } + + internal AssemblyDefinition () + { + } + +#if !READ_ONLY + public static AssemblyDefinition CreateAssembly (AssemblyNameDefinition assemblyName, string moduleName, ModuleKind kind) + { + return CreateAssembly (assemblyName, moduleName, new ModuleParameters { Kind = kind }); + } + + public static AssemblyDefinition CreateAssembly (AssemblyNameDefinition assemblyName, string moduleName, ModuleParameters parameters) + { + if (assemblyName == null) + throw new ArgumentNullException ("assemblyName"); + if (moduleName == null) + throw new ArgumentNullException ("moduleName"); + Mixin.CheckParameters (parameters); + if (parameters.Kind == ModuleKind.NetModule) + throw new ArgumentException ("kind"); + + var assembly = ModuleDefinition.CreateModule (moduleName, parameters).Assembly; + assembly.Name = assemblyName; + + return assembly; + } +#endif + + public static AssemblyDefinition ReadAssembly (string fileName) + { + return ReadAssembly (ModuleDefinition.ReadModule (fileName)); + } + + public static AssemblyDefinition ReadAssembly (string fileName, ReaderParameters parameters) + { + return ReadAssembly (ModuleDefinition.ReadModule (fileName, parameters)); + } + + public static AssemblyDefinition ReadAssembly (Stream stream) + { + return ReadAssembly (ModuleDefinition.ReadModule (stream)); + } + + public static AssemblyDefinition ReadAssembly (Stream stream, ReaderParameters parameters) + { + return ReadAssembly (ModuleDefinition.ReadModule (stream, parameters)); + } + + static AssemblyDefinition ReadAssembly (ModuleDefinition module) + { + var assembly = module.Assembly; + if (assembly == null) + throw new ArgumentException (); + + return assembly; + } + +#if !READ_ONLY + public void Write (string fileName) + { + Write (fileName, new WriterParameters ()); + } + + public void Write (Stream stream) + { + Write (stream, new WriterParameters ()); + } + + public void Write (string fileName, WriterParameters parameters) + { + main_module.Write (fileName, parameters); + } + + public void Write (Stream stream, WriterParameters parameters) + { + main_module.Write (stream, parameters); + } +#endif + + public override string ToString () + { + return this.FullName; + } + } +} diff --git a/Mono.Cecil/AssemblyFlags.cs b/Mono.Cecil/AssemblyFlags.cs new file mode 100644 index 000000000..6d04c59c4 --- /dev/null +++ b/Mono.Cecil/AssemblyFlags.cs @@ -0,0 +1,41 @@ +// +// AssemblyFlags.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace Mono.Cecil { + + [Flags] + public enum AssemblyAttributes : uint { + PublicKey = 0x0001, + SideBySideCompatible = 0x0000, + Retargetable = 0x0100, + DisableJITCompileOptimizer = 0x4000, + EnableJITCompileTracking = 0x8000, + } +} diff --git a/Mono.Cecil/AssemblyHashAlgorithm.cs b/Mono.Cecil/AssemblyHashAlgorithm.cs new file mode 100644 index 000000000..0e7bf838b --- /dev/null +++ b/Mono.Cecil/AssemblyHashAlgorithm.cs @@ -0,0 +1,36 @@ +// +// AssemblyHashAlgorithm.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace Mono.Cecil { + + public enum AssemblyHashAlgorithm : uint { + None = 0x0000, + Reserved = 0x8003, // MD5 + SHA1 = 0x8004 + } +} diff --git a/Mono.Cecil/AssemblyInfo.cs b/Mono.Cecil/AssemblyInfo.cs new file mode 100644 index 000000000..b7019815b --- /dev/null +++ b/Mono.Cecil/AssemblyInfo.cs @@ -0,0 +1,49 @@ +// +// AssemblyInfo.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle ("Mono.Cecil")] +[assembly: AssemblyProduct ("Mono.Cecil")] +[assembly: AssemblyCopyright ("Copyright © 2008 - 2010 Jb Evain")] + +[assembly: ComVisible (false)] + +[assembly: Guid ("fd225bb4-fa53-44b2-a6db-85f5e48dcb54")] + +[assembly: AssemblyVersion ("0.9.4.0")] +#if !CF +[assembly: AssemblyFileVersion ("0.9.4.0")] +#endif + +[assembly: InternalsVisibleTo ("Mono.Cecil.Pdb, PublicKey=002400000480000094000000060200000024000052534131000400000100010079159977d2d03a8e6bea7a2e74e8d1afcc93e8851974952bb480a12c9134474d04062447c37e0e68c080536fcf3c3fbe2ff9c979ce998475e506e8ce82dd5b0f350dc10e93bf2eeecf874b24770c5081dbea7447fddafa277b22de47d6ffea449674a4f9fccf84d15069089380284dbdd35f46cdff12a1bd78e4ef0065d016df")] +[assembly: InternalsVisibleTo ("Mono.Cecil.Mdb, PublicKey=002400000480000094000000060200000024000052534131000400000100010079159977d2d03a8e6bea7a2e74e8d1afcc93e8851974952bb480a12c9134474d04062447c37e0e68c080536fcf3c3fbe2ff9c979ce998475e506e8ce82dd5b0f350dc10e93bf2eeecf874b24770c5081dbea7447fddafa277b22de47d6ffea449674a4f9fccf84d15069089380284dbdd35f46cdff12a1bd78e4ef0065d016df")] +[assembly: InternalsVisibleTo ("Mono.Cecil.Rocks, PublicKey=002400000480000094000000060200000024000052534131000400000100010079159977d2d03a8e6bea7a2e74e8d1afcc93e8851974952bb480a12c9134474d04062447c37e0e68c080536fcf3c3fbe2ff9c979ce998475e506e8ce82dd5b0f350dc10e93bf2eeecf874b24770c5081dbea7447fddafa277b22de47d6ffea449674a4f9fccf84d15069089380284dbdd35f46cdff12a1bd78e4ef0065d016df")] +[assembly: InternalsVisibleTo ("Mono.Cecil.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010079159977d2d03a8e6bea7a2e74e8d1afcc93e8851974952bb480a12c9134474d04062447c37e0e68c080536fcf3c3fbe2ff9c979ce998475e506e8ce82dd5b0f350dc10e93bf2eeecf874b24770c5081dbea7447fddafa277b22de47d6ffea449674a4f9fccf84d15069089380284dbdd35f46cdff12a1bd78e4ef0065d016df")] diff --git a/Mono.Cecil/AssemblyLinkedResource.cs b/Mono.Cecil/AssemblyLinkedResource.cs new file mode 100644 index 000000000..68e44f80b --- /dev/null +++ b/Mono.Cecil/AssemblyLinkedResource.cs @@ -0,0 +1,57 @@ +// +// AssemblyLinkedResource.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace Mono.Cecil { + + public sealed class AssemblyLinkedResource : Resource { + + AssemblyNameReference reference; + + public AssemblyNameReference Assembly { + get { return reference; } + set { reference = value; } + } + + public override ResourceType ResourceType { + get { return ResourceType.AssemblyLinked; } + } + + public AssemblyLinkedResource (string name, ManifestResourceAttributes flags) + : base (name, flags) + { + } + + public AssemblyLinkedResource (string name, ManifestResourceAttributes flags, AssemblyNameReference reference) + : base (name, flags) + { + this.reference = reference; + } + } +} diff --git a/Mono.Cecil/AssemblyNameDefinition.cs b/Mono.Cecil/AssemblyNameDefinition.cs new file mode 100644 index 000000000..4756cb81a --- /dev/null +++ b/Mono.Cecil/AssemblyNameDefinition.cs @@ -0,0 +1,50 @@ +// +// AssemblyNameDefinition.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace Mono.Cecil { + + public sealed class AssemblyNameDefinition : AssemblyNameReference { + + public override byte [] Hash { + get { return Empty.Array; } + } + + internal AssemblyNameDefinition () + { + this.token = new MetadataToken (TokenType.Assembly, 1); + } + + public AssemblyNameDefinition (string name, Version version) + : base (name, version) + { + this.token = new MetadataToken (TokenType.Assembly, 1); + } + } +} diff --git a/Mono.Cecil/AssemblyNameReference.cs b/Mono.Cecil/AssemblyNameReference.cs new file mode 100644 index 000000000..2798082ba --- /dev/null +++ b/Mono.Cecil/AssemblyNameReference.cs @@ -0,0 +1,263 @@ +// +// AssemblyNameReference.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Globalization; +using System.Security.Cryptography; +using System.Text; + +namespace Mono.Cecil { + + public class AssemblyNameReference : IMetadataScope { + + string name; + string culture; + Version version; + uint attributes; + byte [] public_key; + byte [] public_key_token; + AssemblyHashAlgorithm hash_algorithm; + byte [] hash; + + internal MetadataToken token; + + string full_name; + + public string Name { + get { return name; } + set { + name = value; + full_name = null; + } + } + + public string Culture { + get { return culture; } + set { + culture = value; + full_name = null; + } + } + + public Version Version { + get { return version; } + set { + version = value; + full_name = null; + } + } + + public AssemblyAttributes Attributes { + get { return (AssemblyAttributes) attributes; } + set { attributes = (uint) value; } + } + + public bool HasPublicKey { + get { return attributes.GetAttributes ((uint) AssemblyAttributes.PublicKey); } + set { attributes = attributes.SetAttributes ((uint) AssemblyAttributes.PublicKey, value); } + } + + public bool IsSideBySideCompatible { + get { return attributes.GetAttributes ((uint) AssemblyAttributes.SideBySideCompatible); } + set { attributes = attributes.SetAttributes ((uint) AssemblyAttributes.SideBySideCompatible, value); } + } + + public bool IsRetargetable { + get { return attributes.GetAttributes ((uint) AssemblyAttributes.Retargetable); } + set { attributes = attributes.SetAttributes ((uint) AssemblyAttributes.Retargetable, value); } + } + + public byte [] PublicKey { + get { return public_key; } + set { + public_key = value; + HasPublicKey = !public_key.IsNullOrEmpty (); + public_key_token = Empty.Array; + full_name = null; + } + } + + public byte [] PublicKeyToken { + get { + if (public_key_token.IsNullOrEmpty () && !public_key.IsNullOrEmpty ()) { + var hash = HashPublicKey (); + // we need the last 8 bytes in reverse order + public_key_token = new byte [8]; + Array.Copy (hash, (hash.Length - 8), public_key_token, 0, 8); + Array.Reverse (public_key_token, 0, 8); + } + return public_key_token; + } + set { + public_key_token = value; + full_name = null; + } + } + + byte [] HashPublicKey () + { + HashAlgorithm algorithm; + + switch (hash_algorithm) { + case AssemblyHashAlgorithm.Reserved: +#if SILVERLIGHT + throw new NotSupportedException (); +#else + algorithm = MD5.Create (); + break; +#endif + default: + // None default to SHA1 +#if SILVERLIGHT + algorithm = new SHA1Managed (); + break; +#else + algorithm = SHA1.Create (); + break; +#endif + } + + using (algorithm) + return algorithm.ComputeHash (public_key); + } + + public virtual MetadataScopeType MetadataScopeType { + get { return MetadataScopeType.AssemblyNameReference; } + } + + public string FullName { + get { + if (full_name != null) + return full_name; + + const string sep = ", "; + + var builder = new StringBuilder (); + builder.Append (name); + if (version != null) { + builder.Append (sep); + builder.Append ("Version="); + builder.Append (version.ToString ()); + } + builder.Append (sep); + builder.Append ("Culture="); + builder.Append (string.IsNullOrEmpty (culture) ? "neutral" : culture); + builder.Append (sep); + builder.Append ("PublicKeyToken="); + + if (this.PublicKeyToken != null && public_key_token.Length > 0) { + for (int i = 0 ; i < public_key_token.Length ; i++) { + builder.Append (public_key_token [i].ToString ("x2")); + } + } else + builder.Append ("null"); + + return full_name = builder.ToString (); + } + } + + public static AssemblyNameReference Parse (string fullName) + { + if (fullName == null) + throw new ArgumentNullException ("fullName"); + if (fullName.Length == 0) + throw new ArgumentException ("Name can not be empty"); + + var name = new AssemblyNameReference (); + var tokens = fullName.Split (','); + for (int i = 0; i < tokens.Length; i++) { + var token = tokens [i].Trim (); + + if (i == 0) { + name.Name = token; + continue; + } + + var parts = token.Split ('='); + if (parts.Length != 2) + throw new ArgumentException ("Malformed name"); + + switch (parts [0]) { + case "Version": + name.Version = new Version (parts [1]); + break; + case "Culture": + name.Culture = parts [1]; + break; + case "PublicKeyToken": + string pk_token = parts [1]; + if (pk_token == "null") + break; + + name.PublicKeyToken = new byte [pk_token.Length / 2]; + for (int j = 0; j < name.PublicKeyToken.Length; j++) { + name.PublicKeyToken [j] = Byte.Parse (pk_token.Substring (j * 2, 2), NumberStyles.HexNumber); + } + break; + } + } + + return name; + } + + public AssemblyHashAlgorithm HashAlgorithm { + get { return hash_algorithm; } + set { hash_algorithm = value; } + } + + public virtual byte [] Hash { + get { return hash; } + set { hash = value; } + } + + public MetadataToken MetadataToken { + get { return token; } + set { token = value; } + } + + internal AssemblyNameReference () + { + } + + public AssemblyNameReference (string name, Version version) + { + if (name == null) + throw new ArgumentNullException ("name"); + + this.name = name; + this.version = version; + this.hash_algorithm = AssemblyHashAlgorithm.None; + this.token = new MetadataToken (TokenType.AssemblyRef); + } + + public override string ToString () + { + return this.FullName; + } + } +} diff --git a/Mono.Cecil/AssemblyReader.cs b/Mono.Cecil/AssemblyReader.cs new file mode 100644 index 000000000..64e330a60 --- /dev/null +++ b/Mono.Cecil/AssemblyReader.cs @@ -0,0 +1,3047 @@ +// +// AssemblyReader.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +using Mono.Collections.Generic; +using Mono.Cecil.Cil; +using Mono.Cecil.Metadata; +using Mono.Cecil.PE; + +using RVA = System.UInt32; + +namespace Mono.Cecil { + + abstract class ModuleReader { + + readonly protected Image image; + readonly protected ModuleDefinition module; + + protected ModuleReader (Image image, ReadingMode mode) + { + this.image = image; + this.module = new ModuleDefinition (image); + this.module.ReadingMode = mode; + } + + protected abstract void ReadModule (); + + protected void ReadModuleManifest (MetadataReader reader) + { + reader.Populate (module); + + ReadAssembly (reader); + } + + void ReadAssembly (MetadataReader reader) + { + var name = reader.ReadAssemblyNameDefinition (); + if (name == null) { + module.kind = ModuleKind.NetModule; + return; + } + + var assembly = new AssemblyDefinition (); + assembly.Name = name; + + module.assembly = assembly; + assembly.main_module = module; + } + + public static ModuleDefinition CreateModuleFrom (Image image, ReaderParameters parameters) + { + var module = ReadModule (image, parameters); + + ReadSymbols (module, parameters); + + if (parameters.AssemblyResolver != null) + module.assembly_resolver = parameters.AssemblyResolver; + + return module; + } + + static void ReadSymbols (ModuleDefinition module, ReaderParameters parameters) + { + var symbol_reader_provider = parameters.SymbolReaderProvider; + + if (symbol_reader_provider == null && parameters.ReadSymbols) + symbol_reader_provider = SymbolProvider.GetPlatformReaderProvider (); + + if (symbol_reader_provider != null) { + module.SymbolReaderProvider = symbol_reader_provider; + + var reader = parameters.SymbolStream != null + ? symbol_reader_provider.GetSymbolReader (module, parameters.SymbolStream) + : symbol_reader_provider.GetSymbolReader (module, module.FullyQualifiedName); + + module.ReadSymbols (reader); + } + } + + static ModuleDefinition ReadModule (Image image, ReaderParameters parameters) + { + var reader = CreateModuleReader (image, parameters.ReadingMode); + reader.ReadModule (); + return reader.module; + } + + static ModuleReader CreateModuleReader (Image image, ReadingMode mode) + { + switch (mode) { + case ReadingMode.Immediate: + return new ImmediateModuleReader (image); + case ReadingMode.Deferred: + return new DeferredModuleReader (image); + default: + throw new ArgumentException (); + } + } + } + + sealed class ImmediateModuleReader : ModuleReader { + + public ImmediateModuleReader (Image image) + : base (image, ReadingMode.Immediate) + { + } + + protected override void ReadModule () + { + this.module.Read (this.module, (module, reader) => { + ReadModuleManifest (reader); + ReadModule (module); + return module; + }); + } + + public static void ReadModule (ModuleDefinition module) + { + if (module.HasAssemblyReferences) + Read (module.AssemblyReferences); + if (module.HasResources) + Read (module.Resources); + if (module.HasModuleReferences) + Read (module.ModuleReferences); + if (module.HasTypes) + ReadTypes (module.Types); + if (module.HasExportedTypes) + Read (module.ExportedTypes); + if (module.HasCustomAttributes) + Read (module.CustomAttributes); + + var assembly = module.Assembly; + if (assembly == null) + return; + + if (assembly.HasCustomAttributes) + Read (assembly.CustomAttributes); + if (assembly.HasSecurityDeclarations) + Read (assembly.SecurityDeclarations); + } + + static void ReadTypes (Collection types) + { + for (int i = 0; i < types.Count; i++) + ReadType (types [i]); + } + + static void ReadType (TypeDefinition type) + { + ReadGenericParameters (type); + + if (type.HasInterfaces) + Read (type.Interfaces); + + if (type.HasNestedTypes) + ReadTypes (type.NestedTypes); + + if (type.HasLayoutInfo) + Read (type.ClassSize); + + if (type.HasFields) + ReadFields (type); + + if (type.HasMethods) + ReadMethods (type); + + if (type.HasProperties) + ReadProperties (type); + + if (type.HasEvents) + ReadEvents (type); + + ReadSecurityDeclarations (type); + ReadCustomAttributes (type); + } + + static void ReadGenericParameters (IGenericParameterProvider provider) + { + if (!provider.HasGenericParameters) + return; + + var parameters = provider.GenericParameters; + + for (int i = 0; i < parameters.Count; i++) { + var parameter = parameters [i]; + + if (parameter.HasConstraints) + Read (parameter.Constraints); + + if (parameter.HasCustomAttributes) + Read (parameter.CustomAttributes); + } + } + + static void ReadSecurityDeclarations (ISecurityDeclarationProvider provider) + { + if (provider.HasSecurityDeclarations) + Read (provider.SecurityDeclarations); + } + + static void ReadCustomAttributes (ICustomAttributeProvider provider) + { + if (provider.HasCustomAttributes) + Read (provider.CustomAttributes); + } + + static void ReadFields (TypeDefinition type) + { + var fields = type.Fields; + + for (int i = 0; i < fields.Count; i++) { + var field = fields [i]; + + if (field.HasConstant) + Read (field.Constant); + + if (field.HasLayoutInfo) + Read (field.Offset); + + if (field.RVA > 0) + Read (field.InitialValue); + + if (field.HasMarshalInfo) + Read (field.MarshalInfo); + + ReadCustomAttributes (field); + } + } + + static void ReadMethods (TypeDefinition type) + { + var methods = type.Methods; + + for (int i = 0; i < methods.Count; i++) { + var method = methods [i]; + + ReadGenericParameters (method); + + if (method.HasParameters) + ReadParameters (method); + + if (method.HasOverrides) + Read (method.Overrides); + + if (method.IsPInvokeImpl) + Read (method.PInvokeInfo); + + ReadSecurityDeclarations (method); + ReadCustomAttributes (method); + + var return_type = method.MethodReturnType; + if (return_type.HasConstant) + Read (return_type.Constant); + + if (return_type.HasMarshalInfo) + Read (return_type.MarshalInfo); + + ReadCustomAttributes (return_type); + } + } + + static void ReadParameters (MethodDefinition method) + { + var parameters = method.Parameters; + + for (int i = 0; i < parameters.Count; i++) { + var parameter = parameters [i]; + + if (parameter.HasConstant) + Read (parameter.Constant); + + if (parameter.HasMarshalInfo) + Read (parameter.MarshalInfo); + + ReadCustomAttributes (parameter); + } + } + + static void ReadProperties (TypeDefinition type) + { + var properties = type.Properties; + + for (int i = 0; i < properties.Count; i++) { + var property = properties [i]; + + Read (property.GetMethod); + + if (property.HasConstant) + Read (property.Constant); + + ReadCustomAttributes (property); + } + } + + static void ReadEvents (TypeDefinition type) + { + var events = type.Events; + + for (int i = 0; i < events.Count; i++) { + var @event = events [i]; + + Read (@event.AddMethod); + + ReadCustomAttributes (@event); + } + } + + static void Read (object collection) + { + } + } + + sealed class DeferredModuleReader : ModuleReader { + + public DeferredModuleReader (Image image) + : base (image, ReadingMode.Deferred) + { + } + + protected override void ReadModule () + { + this.module.Read (this.module, (module, reader) => { + ReadModuleManifest (reader); + return module; + }); + } + } + + sealed class MetadataReader : ByteBuffer { + + readonly internal Image image; + readonly internal ModuleDefinition module; + readonly internal MetadataSystem metadata; + + internal IGenericContext context; + internal CodeReader code; + + uint Position { + get { return (uint) base.position; } + set { base.position = (int) value; } + } + + public MetadataReader (ModuleDefinition module) + : base (module.Image.MetadataSection.Data) + { + this.image = module.Image; + this.module = module; + this.metadata = module.MetadataSystem; + this.code = CodeReader.CreateCodeReader (this); + } + + int GetCodedIndexSize (CodedIndex index) + { + return image.GetCodedIndexSize (index); + } + + uint ReadByIndexSize (int size) + { + if (size == 4) + return ReadUInt32 (); + else + return ReadUInt16 (); + } + + byte [] ReadBlob () + { + var blob_heap = image.BlobHeap; + if (blob_heap == null) { + position += 2; + return Empty.Array; + } + + return blob_heap.Read (ReadBlobIndex ()); + } + + byte [] ReadBlob (uint signature) + { + var blob_heap = image.BlobHeap; + if (blob_heap == null) + return Empty.Array; + + return blob_heap.Read (signature); + } + + uint ReadBlobIndex () + { + var blob_heap = image.BlobHeap; + return ReadByIndexSize (blob_heap != null ? blob_heap.IndexSize : 2); + } + + string ReadString () + { + return image.StringHeap.Read (ReadByIndexSize (image.StringHeap.IndexSize)); + } + + uint ReadStringIndex () + { + return ReadByIndexSize (image.StringHeap.IndexSize); + } + + uint ReadTableIndex (Table table) + { + return ReadByIndexSize (image.GetTableIndexSize (table)); + } + + MetadataToken ReadMetadataToken (CodedIndex index) + { + return index.GetMetadataToken (ReadByIndexSize (GetCodedIndexSize (index))); + } + + int MoveTo (Table table) + { + var info = image.TableHeap [table]; + if (info.Length != 0) + Position = info.Offset; + + return (int) info.Length; + } + + bool MoveTo (Table table, uint row) + { + var info = image.TableHeap [table]; + var length = info.Length; + if (length == 0 || row > length) + return false; + + Position = info.Offset + (info.RowSize * (row - 1)); + return true; + } + + public AssemblyNameDefinition ReadAssemblyNameDefinition () + { + if (MoveTo (Table.Assembly) == 0) + return null; + + var name = new AssemblyNameDefinition (); + + name.HashAlgorithm = (AssemblyHashAlgorithm) ReadUInt32 (); + + PopulateVersionAndFlags (name); + + name.PublicKey = ReadBlob (); + + PopulateNameAndCulture (name); + + return name; + } + + public ModuleDefinition Populate (ModuleDefinition module) + { + if (MoveTo (Table.Module) == 0) + return module; + + Advance (2); // Generation + + module.Name = ReadString (); + module.Mvid = image.GuidHeap.Read (ReadByIndexSize (image.GuidHeap.IndexSize)); + + return module; + } + + void InitializeAssemblyReferences () + { + if (metadata.AssemblyReferences != null) + return; + + int length = MoveTo (Table.AssemblyRef); + var references = metadata.AssemblyReferences = new AssemblyNameReference [length]; + + for (uint i = 0; i < length; i++) { + var reference = new AssemblyNameReference (); + reference.token = new MetadataToken (TokenType.AssemblyRef, i + 1); + + PopulateVersionAndFlags (reference); + + reference.PublicKeyToken = ReadBlob (); + + PopulateNameAndCulture (reference); + + reference.Hash = ReadBlob (); + + references [i] = reference; + } + } + + public Collection ReadAssemblyReferences () + { + InitializeAssemblyReferences (); + + return new Collection (metadata.AssemblyReferences); + } + + public MethodDefinition ReadEntryPoint () + { + if (module.Kind != ModuleKind.Console && module.Kind != ModuleKind.Windows) + return null; + + var token = new MetadataToken (module.Image.EntryPointToken); + + return GetMethodDefinition (token.RID); + } + + public Collection ReadModules () + { + var modules = new Collection (1); + modules.Add (this.module); + + int length = MoveTo (Table.File); + for (uint i = 1; i <= length; i++) { + var attributes = (FileAttributes) ReadUInt32 (); + var name = ReadString (); + ReadBlobIndex (); + + if (attributes != FileAttributes.ContainsMetaData) + continue; + + var parameters = new ReaderParameters { + ReadingMode = module.ReadingMode, + SymbolReaderProvider = module.SymbolReaderProvider, + }; + + modules.Add (ModuleDefinition.ReadModule ( + GetModuleFileName (name), parameters)); + } + + return modules; + } + + string GetModuleFileName (string name) + { + if (module.FullyQualifiedName == null) + throw new NotSupportedException (); + + var path = Path.GetDirectoryName (module.FullyQualifiedName); + return Path.Combine (path, name); + } + + void InitializeModuleReferences () + { + if (metadata.ModuleReferences != null) + return; + + int length = MoveTo (Table.ModuleRef); + var references = metadata.ModuleReferences = new ModuleReference [length]; + + for (uint i = 0; i < length; i++) { + var reference = new ModuleReference (ReadString ()); + reference.token = new MetadataToken (TokenType.ModuleRef, i + 1); + + references [i] = reference; + } + } + + public Collection ReadModuleReferences () + { + InitializeModuleReferences (); + + return new Collection (metadata.ModuleReferences); + } + + public bool HasFileResource () + { + int length = MoveTo (Table.File); + if (length == 0) + return false; + + for (uint i = 1; i <= length; i++) + if (ReadFileRecord (i).Col1 == FileAttributes.ContainsNoMetaData) + return true; + + return false; + } + + public Collection ReadResources () + { + int length = MoveTo (Table.ManifestResource); + var resources = new Collection (length); + + for (int i = 1; i <= length; i++) { + var offset = ReadUInt32 (); + var flags = (ManifestResourceAttributes) ReadUInt32 (); + var name = ReadString (); + var implementation = ReadMetadataToken (CodedIndex.Implementation); + + Resource resource; + + if (implementation.RID == 0) { + resource = new EmbeddedResource (name, flags, offset, this); + } else if (implementation.TokenType == TokenType.AssemblyRef) { + resource = new AssemblyLinkedResource (name, flags) { + Assembly = (AssemblyNameReference) GetTypeReferenceScope (implementation), + }; + } else if (implementation.TokenType == TokenType.File) { + var file_record = ReadFileRecord (implementation.RID); + + resource = new LinkedResource (name, flags) { + File = file_record.Col2, + hash = ReadBlob (file_record.Col3) + }; + } else + throw new NotSupportedException (); + + resources.Add (resource); + } + + return resources; + } + + Row ReadFileRecord (uint rid) + { + var position = this.position; + + if (!MoveTo (Table.File, rid)) + throw new ArgumentException (); + + var record = new Row ( + (FileAttributes) ReadUInt32 (), + ReadString (), + ReadBlobIndex ()); + + this.position = position; + + return record; + } + + public MemoryStream GetManagedResourceStream (uint offset) + { + var rva = image.Resources.VirtualAddress; + var section = image.GetSectionAtVirtualAddress (rva); + var position = (rva - section.VirtualAddress) + offset; + var buffer = section.Data; + + var length = buffer [position] + | (buffer [position + 1] << 8) + | (buffer [position + 2] << 16) + | (buffer [position + 3] << 24); + + return new MemoryStream (buffer, (int) position + 4, length); + } + + void PopulateVersionAndFlags (AssemblyNameReference name) + { + name.Version = new Version ( + ReadUInt16 (), + ReadUInt16 (), + ReadUInt16 (), + ReadUInt16 ()); + + name.Attributes = (AssemblyAttributes) ReadUInt32 (); + } + + void PopulateNameAndCulture (AssemblyNameReference name) + { + name.Name = ReadString (); + name.Culture = ReadString (); + } + + public TypeDefinitionCollection ReadTypes () + { + InitializeTypeDefinitions (); + var mtypes = metadata.Types; + var type_count = mtypes.Length - metadata.NestedTypes.Count; + var types = new TypeDefinitionCollection (module, type_count); + + for (int i = 0; i < mtypes.Length; i++) { + var type = mtypes [i]; + if (IsNested (type.Attributes)) + continue; + + types.Add (type); + } + + return types; + } + + void InitializeTypeDefinitions () + { + if (metadata.Types != null) + return; + + InitializeNestedTypes (); + InitializeFields (); + InitializeMethods (); + + int length = MoveTo (Table.TypeDef); + var types = metadata.Types = new TypeDefinition [length]; + + for (uint i = 0; i < length; i++) { + if (types [i] != null) + continue; + + types [i] = ReadType (i + 1); + } + } + + static bool IsNested (TypeAttributes attributes) + { + switch (attributes & TypeAttributes.VisibilityMask) { + case TypeAttributes.NestedAssembly: + case TypeAttributes.NestedFamANDAssem: + case TypeAttributes.NestedFamily: + case TypeAttributes.NestedFamORAssem: + case TypeAttributes.NestedPrivate: + case TypeAttributes.NestedPublic: + return true; + default: + return false; + } + } + + public bool HasNestedTypes (TypeDefinition type) + { + uint [] mapping; + InitializeNestedTypes (); + + if (!metadata.TryGetNestedTypeMapping (type, out mapping)) + return false; + + return mapping.Length > 0; + } + + public Collection ReadNestedTypes (TypeDefinition type) + { + InitializeNestedTypes (); + uint [] mapping; + if (!metadata.TryGetNestedTypeMapping (type, out mapping)) + return new MemberDefinitionCollection (type); + + var nested_types = new MemberDefinitionCollection (type, mapping.Length); + + for (int i = 0; i < mapping.Length; i++) + nested_types.Add (GetTypeDefinition (mapping [i])); + + metadata.RemoveNestedTypeMapping (type); + + return nested_types; + } + + void InitializeNestedTypes () + { + if (metadata.NestedTypes != null) + return; + + var length = MoveTo (Table.NestedClass); + + metadata.NestedTypes = new Dictionary (length); + metadata.ReverseNestedTypes = new Dictionary (length); + + if (length == 0) + return; + + for (int i = 1; i <= length; i++) { + var nested = ReadTableIndex (Table.TypeDef); + var declaring = ReadTableIndex (Table.TypeDef); + + AddNestedMapping (declaring, nested); + } + } + + void AddNestedMapping (uint declaring, uint nested) + { + metadata.SetNestedTypeMapping (declaring, AddMapping (metadata.NestedTypes, declaring, nested)); + metadata.SetReverseNestedTypeMapping (nested, declaring); + } + + static TValue [] AddMapping (Dictionary cache, TKey key, TValue value) + { + TValue [] mapped; + if (!cache.TryGetValue (key, out mapped)) { + mapped = new [] { value }; + return mapped; + } + + var new_mapped = new TValue [mapped.Length + 1]; + Array.Copy (mapped, new_mapped, mapped.Length); + new_mapped [mapped.Length] = value; + return new_mapped; + } + + TypeDefinition ReadType (uint rid) + { + if (!MoveTo (Table.TypeDef, rid)) + return null; + + var attributes = (TypeAttributes) ReadUInt32 (); + var name = ReadString (); + var @namespace = ReadString (); + var type = new TypeDefinition (@namespace, name, attributes); + type.token = new MetadataToken (TokenType.TypeDef, rid); + type.scope = module; + type.module = module; + + metadata.AddTypeDefinition (type); + + this.context = type; + + type.BaseType = GetTypeDefOrRef (ReadMetadataToken (CodedIndex.TypeDefOrRef)); + + type.fields_range = ReadFieldsRange (rid); + type.methods_range = ReadMethodsRange (rid); + + if (IsNested (attributes)) + type.DeclaringType = GetNestedTypeDeclaringType (type); + + return type; + } + + TypeDefinition GetNestedTypeDeclaringType (TypeDefinition type) + { + uint declaring_rid; + if (!metadata.TryGetReverseNestedTypeMapping (type, out declaring_rid)) + return null; + + metadata.RemoveReverseNestedTypeMapping (type); + return GetTypeDefinition (declaring_rid); + } + + Range ReadFieldsRange (uint type_index) + { + return ReadListRange (type_index, Table.TypeDef, Table.Field); + } + + Range ReadMethodsRange (uint type_index) + { + return ReadListRange (type_index, Table.TypeDef, Table.Method); + } + + Range ReadListRange (uint current_index, Table current, Table target) + { + var list = new Range (); + + list.Start = ReadTableIndex (target); + + uint next_index; + var current_table = image.TableHeap [current]; + + if (current_index == current_table.Length) + next_index = image.TableHeap [target].Length + 1; + else { + var position = Position; + Position += (uint) (current_table.RowSize - image.GetTableIndexSize (target)); + next_index = ReadTableIndex (target); + Position = position; + } + + list.Length = next_index - list.Start; + + return list; + } + + public Row ReadTypeLayout (TypeDefinition type) + { + InitializeTypeLayouts (); + Row class_layout; + var rid = type.token.RID; + if (!metadata.ClassLayouts.TryGetValue (rid, out class_layout)) + return new Row (Mixin.NoDataMarker, Mixin.NoDataMarker); + + type.PackingSize = (short) class_layout.Col1; + type.ClassSize = (int) class_layout.Col2; + + metadata.ClassLayouts.Remove (rid); + + return new Row ((short) class_layout.Col1, (int) class_layout.Col2); + } + + void InitializeTypeLayouts () + { + if (metadata.ClassLayouts != null) + return; + + int length = MoveTo (Table.ClassLayout); + + var class_layouts = metadata.ClassLayouts = new Dictionary> (length); + + for (uint i = 0; i < length; i++) { + var packing_size = ReadUInt16 (); + var class_size = ReadUInt32 (); + + var parent = ReadTableIndex (Table.TypeDef); + + class_layouts.Add (parent, new Row (packing_size, class_size)); + } + } + + public TypeReference GetTypeDefOrRef (MetadataToken token) + { + return (TypeReference) LookupToken (token); + } + + public TypeDefinition GetTypeDefinition (uint rid) + { + InitializeTypeDefinitions (); + + var type = metadata.GetTypeDefinition (rid); + if (type != null) + return type; + + return ReadTypeDefinition (rid); + } + + TypeDefinition ReadTypeDefinition (uint rid) + { + if (!MoveTo (Table.TypeDef, rid)) + return null; + + return ReadType (rid); + } + + void InitializeTypeReferences () + { + if (metadata.TypeReferences != null) + return; + + metadata.TypeReferences = new TypeReference [image.GetTableLength (Table.TypeRef)]; + } + + public TypeReference GetTypeReference (string scope, string full_name) + { + InitializeTypeReferences (); + + var length = metadata.TypeReferences.Length; + + for (uint i = 1; i <= length; i++) { + var type = GetTypeReference (i); + + if (type.FullName != full_name) + continue; + + if (string.IsNullOrEmpty (scope)) + return type; + + if (type.Scope.Name == scope) + return type; + } + + return null; + } + + TypeReference GetTypeReference (uint rid) + { + InitializeTypeReferences (); + + var type = metadata.GetTypeReference (rid); + if (type != null) + return type; + + return ReadTypeReference (rid); + } + + TypeReference ReadTypeReference (uint rid) + { + if (!MoveTo (Table.TypeRef, rid)) + return null; + + TypeReference declaring_type = null; + IMetadataScope scope; + + var scope_token = ReadMetadataToken (CodedIndex.ResolutionScope); + + var name = ReadString (); + var @namespace = ReadString (); + + var type = new TypeReference ( + @namespace, + name, + module, + null); + + type.token = new MetadataToken (TokenType.TypeRef, rid); + + metadata.AddTypeReference (type); + + if (scope_token.TokenType == TokenType.TypeRef) { + declaring_type = GetTypeDefOrRef (scope_token); + + scope = declaring_type != null + ? declaring_type.Scope + : module; + } else + scope = GetTypeReferenceScope (scope_token); + + type.scope = scope; + type.DeclaringType = declaring_type; + + MetadataSystem.TryProcessPrimitiveType (type); + + return type; + } + + IMetadataScope GetTypeReferenceScope (MetadataToken scope) + { + switch (scope.TokenType) { + case TokenType.AssemblyRef: + InitializeAssemblyReferences (); + return metadata.AssemblyReferences [(int) scope.RID - 1]; + case TokenType.ModuleRef: + InitializeModuleReferences (); + return metadata.ModuleReferences [(int) scope.RID - 1]; + case TokenType.Module: + return module; + default: + throw new NotSupportedException (); + } + } + + public IEnumerable GetTypeReferences () + { + InitializeTypeReferences (); + + var length = image.GetTableLength (Table.TypeRef); + + var type_references = new TypeReference [length]; + + for (uint i = 1; i <= length; i++) + type_references [i - 1] = GetTypeReference (i); + + return type_references; + } + + TypeReference GetTypeSpecification (uint rid) + { + if (!MoveTo (Table.TypeSpec, rid)) + return null; + + var reader = ReadSignature (ReadBlobIndex ()); + var type = reader.ReadTypeSignature (); + if (type.token.RID == 0) + type.token = new MetadataToken (TokenType.TypeSpec, rid); + + return type; + } + + SignatureReader ReadSignature (uint signature) + { + return new SignatureReader (signature, this); + } + + public bool HasInterfaces (TypeDefinition type) + { + InitializeInterfaces (); + MetadataToken [] mapping; + + return metadata.TryGetInterfaceMapping (type, out mapping); + } + + public Collection ReadInterfaces (TypeDefinition type) + { + InitializeInterfaces (); + MetadataToken [] mapping; + + if (!metadata.TryGetInterfaceMapping (type, out mapping)) + return new Collection (); + + var interfaces = new Collection (mapping.Length); + + this.context = type; + + for (int i = 0; i < mapping.Length; i++) + interfaces.Add (GetTypeDefOrRef (mapping [i])); + + metadata.RemoveInterfaceMapping (type); + + return interfaces; + } + + void InitializeInterfaces () + { + if (metadata.Interfaces != null) + return; + + int length = MoveTo (Table.InterfaceImpl); + + metadata.Interfaces = new Dictionary (length); + + for (int i = 0; i < length; i++) { + var type = ReadTableIndex (Table.TypeDef); + var @interface = ReadMetadataToken (CodedIndex.TypeDefOrRef); + + AddInterfaceMapping (type, @interface); + } + } + + void AddInterfaceMapping (uint type, MetadataToken @interface) + { + metadata.SetInterfaceMapping (type, AddMapping (metadata.Interfaces, type, @interface)); + } + + public Collection ReadFields (TypeDefinition type) + { + var fields_range = type.fields_range; + if (fields_range.Length == 0) + return new MemberDefinitionCollection (type); + + var fields = new MemberDefinitionCollection (type, (int) fields_range.Length); + this.context = type; + + MoveTo (Table.Field, fields_range.Start); + for (uint i = 0; i < fields_range.Length; i++) + fields.Add (ReadField (fields_range.Start + i)); + + return fields; + } + + FieldDefinition ReadField (uint field_rid) + { + var attributes = (FieldAttributes) ReadUInt16 (); + var name = ReadString (); + var signature = ReadBlobIndex (); + + var field = new FieldDefinition (name, attributes, ReadFieldType (signature)); + field.token = new MetadataToken (TokenType.Field, field_rid); + metadata.AddFieldDefinition (field); + + return field; + } + + void InitializeFields () + { + if (metadata.Fields != null) + return; + + metadata.Fields = new FieldDefinition [image.GetTableLength (Table.Field)]; + } + + TypeReference ReadFieldType (uint signature) + { + var reader = ReadSignature (signature); + + const byte field_sig = 0x6; + + if (reader.ReadByte () != field_sig) + throw new NotSupportedException (); + + return reader.ReadTypeSignature (); + } + + public int ReadFieldRVA (FieldDefinition field) + { + InitializeFieldRVAs (); + var rid = field.token.RID; + + RVA rva; + if (!metadata.FieldRVAs.TryGetValue (rid, out rva)) + return 0; + + var size = GetFieldTypeSize (field.FieldType); + + if (size == 0 || rva == 0) + return 0; + + metadata.FieldRVAs.Remove (rid); + + field.InitialValue = GetFieldInitializeValue (size, rva); + + return (int) rva; + } + + byte [] GetFieldInitializeValue (int size, RVA rva) + { + var section = image.GetSectionAtVirtualAddress (rva); + if (section == null) + return Empty.Array; + + var value = new byte [size]; + Buffer.BlockCopy (section.Data, (int) (rva - section.VirtualAddress), value, 0, size); + return value; + } + + static int GetFieldTypeSize (TypeReference type) + { + int size = 0; + + switch (type.etype) { + case ElementType.Boolean: + case ElementType.U1: + case ElementType.I1: + size = 1; + break; + case ElementType.U2: + case ElementType.I2: + case ElementType.Char: + size = 2; + break; + case ElementType.U4: + case ElementType.I4: + case ElementType.R4: + size = 4; + break; + case ElementType.U8: + case ElementType.I8: + case ElementType.R8: + size = 8; + break; + case ElementType.Ptr: + case ElementType.FnPtr: + size = IntPtr.Size; + break; + case ElementType.CModOpt: + case ElementType.CModReqD: + return GetFieldTypeSize (((IModifierType) type).ElementType); + default: + var field_type = type.CheckedResolve (); + if (field_type.HasLayoutInfo) + size = field_type.ClassSize; + + break; + } + + return size; + } + + void InitializeFieldRVAs () + { + if (metadata.FieldRVAs != null) + return; + + int length = MoveTo (Table.FieldRVA); + + var field_rvas = metadata.FieldRVAs = new Dictionary (length); + + for (int i = 0; i < length; i++) { + var rva = ReadUInt32 (); + var field = ReadTableIndex (Table.Field); + + field_rvas.Add (field, rva); + } + } + + public int ReadFieldLayout (FieldDefinition field) + { + InitializeFieldLayouts (); + var rid = field.token.RID; + uint offset; + if (!metadata.FieldLayouts.TryGetValue (rid, out offset)) + return Mixin.NoDataMarker; + + metadata.FieldLayouts.Remove (rid); + + return (int) offset; + } + + void InitializeFieldLayouts () + { + if (metadata.FieldLayouts != null) + return; + + int length = MoveTo (Table.FieldLayout); + + var field_layouts = metadata.FieldLayouts = new Dictionary (length); + + for (int i = 0; i < length; i++) { + var offset = ReadUInt32 (); + var field = ReadTableIndex (Table.Field); + + field_layouts.Add (field, offset); + } + } + + public bool HasEvents (TypeDefinition type) + { + InitializeEvents (); + + Range range; + if (!metadata.TryGetEventsRange (type, out range)) + return false; + + return range.Length > 0; + } + + public Collection ReadEvents (TypeDefinition type) + { + InitializeEvents (); + Range range; + + if (!metadata.TryGetEventsRange (type, out range)) + return new MemberDefinitionCollection (type); + + var events = new MemberDefinitionCollection (type, (int) range.Length); + + metadata.RemoveEventsRange (type); + + if (range.Length == 0 || !MoveTo (Table.Event, range.Start)) + return events; + + this.context = type; + + for (uint i = 0; i < range.Length; i++) + events.Add (ReadEvent (range.Start + i)); + + return events; + } + + EventDefinition ReadEvent (uint event_rid) + { + var attributes = (EventAttributes) ReadUInt16 (); + var name = ReadString (); + var event_type = GetTypeDefOrRef (ReadMetadataToken (CodedIndex.TypeDefOrRef)); + + var @event = new EventDefinition (name, attributes, event_type); + @event.token = new MetadataToken (TokenType.Event, event_rid); + return @event; + } + + void InitializeEvents () + { + if (metadata.Events != null) + return; + + int length = MoveTo (Table.EventMap); + + metadata.Events = new Dictionary (length); + + for (uint i = 1; i <= length; i++) { + var type_rid = ReadTableIndex (Table.TypeDef); + Range events_range = ReadEventsRange (i); + metadata.AddEventsRange (type_rid, events_range); + } + } + + Range ReadEventsRange (uint rid) + { + return ReadListRange (rid, Table.EventMap, Table.Event); + } + + public bool HasProperties (TypeDefinition type) + { + InitializeProperties (); + + Range range; + if (!metadata.TryGetPropertiesRange (type, out range)) + return false; + + return range.Length > 0; + } + + public Collection ReadProperties (TypeDefinition type) + { + InitializeProperties (); + + Range range; + + if (!metadata.TryGetPropertiesRange (type, out range)) + return new MemberDefinitionCollection (type); + + metadata.RemovePropertiesRange (type); + + var properties = new MemberDefinitionCollection (type, (int) range.Length); + + if (range.Length == 0 || !MoveTo (Table.Property, range.Start)) + return properties; + + this.context = type; + + for (uint i = 0; i < range.Length; i++) + properties.Add (ReadProperty (range.Start + i)); + + return properties; + } + + PropertyDefinition ReadProperty (uint property_rid) + { + var attributes = (PropertyAttributes) ReadUInt16 (); + var name = ReadString (); + var signature = ReadBlobIndex (); + + var reader = ReadSignature (signature); + const byte property_signature = 0x8; + + var calling_convention = reader.ReadByte (); + + if ((calling_convention & property_signature) == 0) + throw new NotSupportedException (); + + var has_this = (calling_convention & 0x20) != 0; + + reader.ReadCompressedUInt32 (); // count + + var property = new PropertyDefinition (name, attributes, reader.ReadTypeSignature ()); + property.HasThis = has_this; + property.token = new MetadataToken (TokenType.Property, property_rid); + + return property; + } + + void InitializeProperties () + { + if (metadata.Properties != null) + return; + + int length = MoveTo (Table.PropertyMap); + + metadata.Properties = new Dictionary (length); + + for (uint i = 1; i <= length; i++) { + var type_rid = ReadTableIndex (Table.TypeDef); + var properties_range = ReadPropertiesRange (i); + metadata.AddPropertiesRange (type_rid, properties_range); + } + } + + Range ReadPropertiesRange (uint rid) + { + return ReadListRange (rid, Table.PropertyMap, Table.Property); + } + + MethodSemanticsAttributes ReadMethodSemantics (MethodDefinition method) + { + InitializeMethodSemantics (); + Row row; + if (!metadata.Semantics.TryGetValue (method.token.RID, out row)) + return MethodSemanticsAttributes.None; + + var type = method.DeclaringType; + + switch (row.Col1) { + case MethodSemanticsAttributes.AddOn: + GetEvent (type, row.Col2).add_method = method; + break; + case MethodSemanticsAttributes.Fire: + GetEvent (type, row.Col2).invoke_method = method; + break; + case MethodSemanticsAttributes.RemoveOn: + GetEvent (type, row.Col2).remove_method = method; + break; + case MethodSemanticsAttributes.Getter: + GetProperty (type, row.Col2).get_method = method; + break; + case MethodSemanticsAttributes.Setter: + GetProperty (type, row.Col2).set_method = method; + break; + case MethodSemanticsAttributes.Other: + switch (row.Col2.TokenType) { + case TokenType.Event: { + var @event = GetEvent (type, row.Col2); + if (@event.other_methods == null) + @event.other_methods = new Collection (); + + @event.other_methods.Add (method); + break; + } + case TokenType.Property: { + var property = GetProperty (type, row.Col2); + if (property.other_methods == null) + property.other_methods = new Collection (); + + property.other_methods.Add (method); + + break; + } + default: + throw new NotSupportedException (); + } + break; + default: + throw new NotSupportedException (); + } + + metadata.Semantics.Remove (method.token.RID); + + return row.Col1; + } + + static EventDefinition GetEvent (TypeDefinition type, MetadataToken token) + { + if (token.TokenType != TokenType.Event) + throw new ArgumentException (); + + return GetMember (type.Events, token); + } + + static PropertyDefinition GetProperty (TypeDefinition type, MetadataToken token) + { + if (token.TokenType != TokenType.Property) + throw new ArgumentException (); + + return GetMember (type.Properties, token); + } + + static TMember GetMember (Collection members, MetadataToken token) where TMember : IMemberDefinition + { + for (int i = 0; i < members.Count; i++) { + var member = members [i]; + if (member.MetadataToken == token) + return member; + } + + throw new ArgumentException (); + } + + void InitializeMethodSemantics () + { + if (metadata.Semantics != null) + return; + + int length = MoveTo (Table.MethodSemantics); + + var semantics = metadata.Semantics = new Dictionary> (0); + + for (uint i = 0; i < length; i++) { + var attributes = (MethodSemanticsAttributes) ReadUInt16 (); + var method_rid = ReadTableIndex (Table.Method); + var association = ReadMetadataToken (CodedIndex.HasSemantics); + + semantics [method_rid] = new Row (attributes, association); + } + } + + public PropertyDefinition ReadMethods (PropertyDefinition property) + { + ReadAllSemantics (property.DeclaringType); + return property; + } + + public EventDefinition ReadMethods (EventDefinition @event) + { + ReadAllSemantics (@event.DeclaringType); + return @event; + } + + public MethodSemanticsAttributes ReadAllSemantics (MethodDefinition method) + { + ReadAllSemantics (method.DeclaringType); + + return method.SemanticsAttributes; + } + + void ReadAllSemantics (TypeDefinition type) + { + var methods = type.Methods; + for (int i = 0; i < methods.Count; i++) { + var method = methods [i]; + if (method.sem_attrs.HasValue) + continue; + + method.sem_attrs = ReadMethodSemantics (method); + } + } + + Range ReadParametersRange (uint method_rid) + { + return ReadListRange (method_rid, Table.Method, Table.Param); + } + + public Collection ReadMethods (TypeDefinition type) + { + var methods_range = type.methods_range; + if (methods_range.Length == 0) + return new MemberDefinitionCollection (type); + + var methods = new MemberDefinitionCollection (type, (int) methods_range.Length); + + MoveTo (Table.Method, methods_range.Start); + for (uint i = 0; i < methods_range.Length; i++) + ReadMethod (methods_range.Start + i, methods); + + return methods; + } + + void InitializeMethods () + { + if (metadata.Methods != null) + return; + + metadata.Methods = new MethodDefinition [image.GetTableLength (Table.Method)]; + } + + void ReadMethod (uint method_rid, Collection methods) + { + var method = new MethodDefinition (); + method.rva = ReadUInt32 (); + method.ImplAttributes = (MethodImplAttributes) ReadUInt16 (); + method.Attributes = (MethodAttributes) ReadUInt16 (); + method.Name = ReadString (); + method.token = new MetadataToken (TokenType.Method, method_rid); + + methods.Add (method); // attach method + + var signature = ReadBlobIndex (); + var param_range = ReadParametersRange (method_rid); + + this.context = method; + + ReadMethodSignature (signature, method); + metadata.AddMethodDefinition (method); + + if (param_range.Length == 0) + return; + + var position = base.position; + ReadParameters (method, param_range); + base.position = position; + } + + void ReadParameters (MethodDefinition method, Range param_range) + { + MoveTo (Table.Param, param_range.Start); + for (uint i = 0; i < param_range.Length; i++) { + var attributes = (ParameterAttributes) ReadUInt16 (); + var sequence = ReadUInt16 (); + var name = ReadString (); + + var parameter = sequence == 0 + ? method.MethodReturnType.Parameter + : method.Parameters [sequence - 1]; + + parameter.token = new MetadataToken (TokenType.Param, param_range.Start + i); + parameter.Name = name; + parameter.Attributes = attributes; + } + } + + void ReadMethodSignature (uint signature, IMethodSignature method) + { + var reader = ReadSignature (signature); + reader.ReadMethodSignature (method); + } + + public PInvokeInfo ReadPInvokeInfo (MethodDefinition method) + { + InitializePInvokes (); + Row row; + + var rid = method.token.RID; + + if (!metadata.PInvokes.TryGetValue (rid, out row)) + return null; + + metadata.PInvokes.Remove (rid); + + return new PInvokeInfo ( + row.Col1, + image.StringHeap.Read (row.Col2), + module.ModuleReferences [(int) row.Col3 - 1]); + } + + void InitializePInvokes () + { + if (metadata.PInvokes != null) + return; + + int length = MoveTo (Table.ImplMap); + + var pinvokes = metadata.PInvokes = new Dictionary> (length); + + for (int i = 1; i <= length; i++) { + var attributes = (PInvokeAttributes) ReadUInt16 (); + var method = ReadMetadataToken (CodedIndex.MemberForwarded); + var name = ReadStringIndex (); + var scope = ReadTableIndex (Table.File); + + if (method.TokenType != TokenType.Method) + continue; + + pinvokes.Add (method.RID, new Row (attributes, name, scope)); + } + } + + public bool HasGenericParameters (IGenericParameterProvider provider) + { + InitializeGenericParameters (); + + Range range; + if (!metadata.TryGetGenericParameterRange (provider, out range)) + return false; + + return range.Length > 0; + } + + public Collection ReadGenericParameters (IGenericParameterProvider provider) + { + InitializeGenericParameters (); + + Range range; + if (!metadata.TryGetGenericParameterRange (provider, out range) + || !MoveTo (Table.GenericParam, range.Start)) + return new Collection (); + + metadata.RemoveGenericParameterRange (provider); + + var generic_parameters = new Collection ((int) range.Length); + + for (uint i = 0; i < range.Length; i++) { + ReadUInt16 (); // index + var flags = (GenericParameterAttributes) ReadUInt16 (); + ReadMetadataToken (CodedIndex.TypeOrMethodDef); + var name = ReadString (); + + var parameter = new GenericParameter (name, provider); + parameter.token = new MetadataToken (TokenType.GenericParam, range.Start + i); + parameter.Attributes = flags; + + generic_parameters.Add (parameter); + } + + return generic_parameters; + } + + void InitializeGenericParameters () + { + if (metadata.GenericParameters != null) + return; + + metadata.GenericParameters = InitializeRanges ( + Table.GenericParam, () => { + Advance (4); + var next = ReadMetadataToken (CodedIndex.TypeOrMethodDef); + ReadStringIndex (); + return next; + }); + } + + Dictionary InitializeRanges (Table table, Func get_next) + { + int length = MoveTo (table); + var ranges = new Dictionary (length); + + if (length == 0) + return ranges; + + MetadataToken owner = MetadataToken.Zero; + Range range = new Range (1, 0); + + for (uint i = 1; i <= length; i++) { + var next = get_next (); + + if (i == 1) { + owner = next; + range.Length++; + } else if (next != owner) { + if (owner.RID != 0) + ranges.Add (owner, range); + range = new Range (i, 1); + owner = next; + } else + range.Length++; + } + + if (owner != MetadataToken.Zero) + ranges.Add (owner, range); + + return ranges; + } + + public bool HasGenericConstraints (GenericParameter generic_parameter) + { + InitializeGenericConstraints (); + + MetadataToken [] mapping; + if (!metadata.TryGetGenericConstraintMapping (generic_parameter, out mapping)) + return false; + + return mapping.Length > 0; + } + + public Collection ReadGenericConstraints (GenericParameter generic_parameter) + { + InitializeGenericConstraints (); + + MetadataToken [] mapping; + if (!metadata.TryGetGenericConstraintMapping (generic_parameter, out mapping)) + return new Collection (); + + var constraints = new Collection (mapping.Length); + + this.context = (IGenericContext) generic_parameter.Owner; + + for (int i = 0; i < mapping.Length; i++) + constraints.Add (GetTypeDefOrRef (mapping [i])); + + metadata.RemoveGenericConstraintMapping (generic_parameter); + + return constraints; + } + + void InitializeGenericConstraints () + { + if (metadata.GenericConstraints != null) + return; + + var length = MoveTo (Table.GenericParamConstraint); + + metadata.GenericConstraints = new Dictionary (length); + + for (int i = 1; i <= length; i++) + AddGenericConstraintMapping ( + ReadTableIndex (Table.GenericParam), + ReadMetadataToken (CodedIndex.TypeDefOrRef)); + } + + void AddGenericConstraintMapping (uint generic_parameter, MetadataToken constraint) + { + metadata.SetGenericConstraintMapping ( + generic_parameter, + AddMapping (metadata.GenericConstraints, generic_parameter, constraint)); + } + + public bool HasOverrides (MethodDefinition method) + { + InitializeOverrides (); + MetadataToken [] mapping; + + if (!metadata.TryGetOverrideMapping (method, out mapping)) + return false; + + return mapping.Length > 0; + } + + public Collection ReadOverrides (MethodDefinition method) + { + InitializeOverrides (); + + MetadataToken [] mapping; + if (!metadata.TryGetOverrideMapping (method, out mapping)) + return new Collection (); + + var overrides = new Collection (mapping.Length); + + this.context = method; + + for (int i = 0; i < mapping.Length; i++) + overrides.Add ((MethodReference) LookupToken (mapping [i])); + + metadata.RemoveOverrideMapping (method); + + return overrides; + } + + void InitializeOverrides () + { + if (metadata.Overrides != null) + return; + + var length = MoveTo (Table.MethodImpl); + + metadata.Overrides = new Dictionary (length); + + for (int i = 1; i <= length; i++) { + ReadTableIndex (Table.TypeDef); + + var method = ReadMetadataToken (CodedIndex.MethodDefOrRef); + if (method.TokenType != TokenType.Method) + throw new NotSupportedException (); + + var @override = ReadMetadataToken (CodedIndex.MethodDefOrRef); + + AddOverrideMapping (method.RID, @override); + } + } + + void AddOverrideMapping (uint method_rid, MetadataToken @override) + { + metadata.SetOverrideMapping ( + method_rid, + AddMapping (metadata.Overrides, method_rid, @override)); + } + + public MethodBody ReadMethodBody (MethodDefinition method) + { + return code.ReadMethodBody (method); + } + + public CallSite ReadCallSite (MetadataToken token) + { + if (!MoveTo (Table.StandAloneSig, token.RID)) + return null; + + var signature = ReadBlobIndex (); + + var call_site = new CallSite (); + + ReadMethodSignature (signature, call_site); + + call_site.MetadataToken = token; + + return call_site; + } + + public VariableDefinitionCollection ReadVariables (MetadataToken local_var_token) + { + if (!MoveTo (Table.StandAloneSig, local_var_token.RID)) + return null; + + var reader = ReadSignature (ReadBlobIndex ()); + const byte local_sig = 0x7; + + if (reader.ReadByte () != local_sig) + throw new NotSupportedException (); + + var count = reader.ReadCompressedUInt32 (); + if (count == 0) + return null; + + var variables = new VariableDefinitionCollection ((int) count); + + for (int i = 0; i < count; i++) + variables.Add (new VariableDefinition (reader.ReadTypeSignature ())); + + return variables; + } + + public IMetadataTokenProvider LookupToken (MetadataToken token) + { + var rid = token.RID; + + if (rid == 0) + return null; + + IMetadataTokenProvider element; + var position = this.position; + var context = this.context; + + switch (token.TokenType) { + case TokenType.TypeDef: + element = GetTypeDefinition (rid); + break; + case TokenType.TypeRef: + element = GetTypeReference (rid); + break; + case TokenType.TypeSpec: + element = GetTypeSpecification (rid); + break; + case TokenType.Field: + element = GetFieldDefinition (rid); + break; + case TokenType.Method: + element = GetMethodDefinition (rid); + break; + case TokenType.MemberRef: + element = GetMemberReference (rid); + break; + case TokenType.MethodSpec: + element = GetMethodSpecification (rid); + break; + default: + return null; + } + + this.position = position; + this.context = context; + + return element; + } + + public FieldDefinition GetFieldDefinition (uint rid) + { + InitializeTypeDefinitions (); + + var field = metadata.GetFieldDefinition (rid); + if (field != null) + return field; + + return LookupField (rid); + } + + FieldDefinition LookupField (uint rid) + { + var type = metadata.GetFieldDeclaringType (rid); + if (type == null) + return null; + + InitializeCollection (type.Fields); + + return metadata.GetFieldDefinition (rid); + } + + public MethodDefinition GetMethodDefinition (uint rid) + { + InitializeTypeDefinitions (); + + var method = metadata.GetMethodDefinition (rid); + if (method != null) + return method; + + return LookupMethod (rid); + } + + MethodDefinition LookupMethod (uint rid) + { + var type = metadata.GetMethodDeclaringType (rid); + if (type == null) + return null; + + InitializeCollection (type.Methods); + + return metadata.GetMethodDefinition (rid); + } + + MethodSpecification GetMethodSpecification (uint rid) + { + if (!MoveTo (Table.MethodSpec, rid)) + return null; + + var element_method = (MethodReference) LookupToken ( + ReadMetadataToken (CodedIndex.MethodDefOrRef)); + var signature = ReadBlobIndex (); + + var method_spec = ReadMethodSpecSignature (signature, element_method); + method_spec.token = new MetadataToken (TokenType.MethodSpec, rid); + return method_spec; + } + + MethodSpecification ReadMethodSpecSignature (uint signature, MethodReference method) + { + var reader = ReadSignature (signature); + const byte methodspec_sig = 0x0a; + + var call_conv = reader.ReadByte (); + + if (call_conv != methodspec_sig) + throw new NotSupportedException (); + + var instance = new GenericInstanceMethod (method); + + reader.ReadGenericInstanceSignature (method, instance); + + return instance; + } + + MemberReference GetMemberReference (uint rid) + { + InitializeMemberReferences (); + + var member = metadata.GetMemberReference (rid); + if (member != null) + return member; + + member = ReadMemberReference (rid); + if (member != null && !member.ContainsGenericParameter) + metadata.AddMemberReference (member); + return member; + } + + MemberReference ReadMemberReference (uint rid) + { + if (!MoveTo (Table.MemberRef, rid)) + return null; + + var token = ReadMetadataToken (CodedIndex.MemberRefParent); + var name = ReadString (); + var signature = ReadBlobIndex (); + + MemberReference member; + + switch (token.TokenType) { + case TokenType.TypeDef: + case TokenType.TypeRef: + case TokenType.TypeSpec: + member = ReadTypeMemberReference (token, name, signature); + break; + case TokenType.Method: + member = ReadMethodMemberReference (token, name, signature); + break; + default: + throw new NotSupportedException (); + } + + member.token = new MetadataToken (TokenType.MemberRef, rid); + + return member; + } + + MemberReference ReadTypeMemberReference (MetadataToken type, string name, uint signature) + { + var declaring_type = GetTypeDefOrRef (type); + + this.context = declaring_type; + + var member = ReadMemberReferenceSignature (signature, declaring_type); + member.Name = name; + + return member; + } + + MemberReference ReadMemberReferenceSignature (uint signature, TypeReference declaring_type) + { + var reader = ReadSignature (signature); + const byte field_sig = 0x6; + + if (reader.buffer [reader.position] == field_sig) { + reader.position++; + var field = new FieldReference (); + field.DeclaringType = declaring_type; + field.FieldType = reader.ReadTypeSignature (); + return field; + } else { + var method = new MethodReference (); + method.DeclaringType = declaring_type; + reader.ReadMethodSignature (method); + return method; + } + } + + MemberReference ReadMethodMemberReference (MetadataToken token, string name, uint signature) + { + var method = GetMethodDefinition (token.RID); + + this.context = method; + + var member = ReadMemberReferenceSignature (signature, method.DeclaringType); + member.Name = name; + + return member; + } + + void InitializeMemberReferences () + { + if (metadata.MemberReferences != null) + return; + + metadata.MemberReferences = new MemberReference [image.GetTableLength (Table.MemberRef)]; + } + + public IEnumerable GetMemberReferences () + { + InitializeMemberReferences (); + + var length = image.GetTableLength (Table.MemberRef); + + var type_system = module.TypeSystem; + + var context = new MethodReference (string.Empty, type_system.Void); + context.DeclaringType = new TypeReference (string.Empty, string.Empty, module, type_system.Corlib); + + var member_references = new MemberReference [length]; + + for (uint i = 1; i <= length; i++) { + this.context = context; + member_references [i - 1] = GetMemberReference (i); + } + + return member_references; + } + + void InitializeConstants () + { + if (metadata.Constants != null) + return; + + var length = MoveTo (Table.Constant); + + var constants = metadata.Constants = new Dictionary> (length); + + for (uint i = 1; i <= length; i++) { + var type = (ElementType) ReadUInt16 (); + var owner = ReadMetadataToken (CodedIndex.HasConstant); + var signature = ReadBlobIndex (); + + constants.Add (owner, new Row (type, signature)); + } + } + + public object ReadConstant (IConstantProvider owner) + { + InitializeConstants (); + + Row row; + if (!metadata.Constants.TryGetValue (owner.MetadataToken, out row)) + return Mixin.NoValue; + + metadata.Constants.Remove (owner.MetadataToken); + + switch (row.Col1) { + case ElementType.Class: + case ElementType.Object: + return null; + case ElementType.String: + return ReadConstantString (ReadBlob (row.Col2)); + default: + return ReadConstantPrimitive (row.Col1, row.Col2); + } + } + + static string ReadConstantString (byte [] blob) + { + var length = blob.Length; + if ((length & 1) == 1) + length--; + + return Encoding.Unicode.GetString (blob, 0, length); + } + + object ReadConstantPrimitive (ElementType type, uint signature) + { + var reader = ReadSignature (signature); + return reader.ReadConstantSignature (type); + } + + void InitializeCustomAttributes () + { + if (metadata.CustomAttributes != null) + return; + + metadata.CustomAttributes = InitializeRanges ( + Table.CustomAttribute, () => { + var next = ReadMetadataToken (CodedIndex.HasCustomAttribute); + ReadMetadataToken (CodedIndex.CustomAttributeType); + ReadBlobIndex (); + return next; + }); + } + + public bool HasCustomAttributes (ICustomAttributeProvider owner) + { + InitializeCustomAttributes (); + + Range range; + if (!metadata.TryGetCustomAttributeRange (owner, out range)) + return false; + + return range.Length > 0; + } + + public Collection ReadCustomAttributes (ICustomAttributeProvider owner) + { + InitializeCustomAttributes (); + + Range range; + if (!metadata.TryGetCustomAttributeRange (owner, out range) + || !MoveTo (Table.CustomAttribute, range.Start)) + return new Collection (); + + var custom_attributes = new Collection ((int) range.Length); + + for (int i = 0; i < range.Length; i++) { + ReadMetadataToken (CodedIndex.HasCustomAttribute); + + var constructor = (MethodReference) LookupToken ( + ReadMetadataToken (CodedIndex.CustomAttributeType)); + + var signature = ReadBlobIndex (); + + custom_attributes.Add (new CustomAttribute (signature, constructor)); + } + + metadata.RemoveCustomAttributeRange (owner); + + return custom_attributes; + } + + public byte [] ReadCustomAttributeBlob (uint signature) + { + return ReadBlob (signature); + } + + public void ReadCustomAttributeSignature (CustomAttribute attribute) + { + var reader = ReadSignature (attribute.signature); + if (reader.ReadUInt16 () != 0x0001) + throw new InvalidOperationException (); + + var constructor = attribute.Constructor; + if (constructor.HasParameters) + reader.ReadCustomAttributeConstructorArguments (attribute, constructor.Parameters); + + if (!reader.CanReadMore ()) + return; + + var named = reader.ReadUInt16 (); + + if (named == 0) + return; + + reader.ReadCustomAttributeNamedArguments (named, ref attribute.fields, ref attribute.properties); + } + + void InitializeMarshalInfos () + { + if (metadata.FieldMarshals != null) + return; + + var length = MoveTo (Table.FieldMarshal); + + var marshals = metadata.FieldMarshals = new Dictionary (length); + + for (int i = 0; i < length; i++) { + var token = ReadMetadataToken (CodedIndex.HasFieldMarshal); + var signature = ReadBlobIndex (); + if (token.RID == 0) + continue; + + marshals.Add (token, signature); + } + } + + public bool HasMarshalInfo (IMarshalInfoProvider owner) + { + InitializeMarshalInfos (); + + return metadata.FieldMarshals.ContainsKey (owner.MetadataToken); + } + + public MarshalInfo ReadMarshalInfo (IMarshalInfoProvider owner) + { + InitializeMarshalInfos (); + + uint signature; + if (!metadata.FieldMarshals.TryGetValue (owner.MetadataToken, out signature)) + return null; + + var reader = ReadSignature (signature); + + metadata.FieldMarshals.Remove (owner.MetadataToken); + + return reader.ReadMarshalInfo (); + } + + void InitializeSecurityDeclarations () + { + if (metadata.SecurityDeclarations != null) + return; + + metadata.SecurityDeclarations = InitializeRanges ( + Table.DeclSecurity, () => { + ReadUInt16 (); + var next = ReadMetadataToken (CodedIndex.HasDeclSecurity); + ReadBlobIndex (); + return next; + }); + } + + public bool HasSecurityDeclarations (ISecurityDeclarationProvider owner) + { + InitializeSecurityDeclarations (); + + Range range; + if (!metadata.TryGetSecurityDeclarationRange (owner, out range)) + return false; + + return range.Length > 0; + } + + public Collection ReadSecurityDeclarations (ISecurityDeclarationProvider owner) + { + InitializeSecurityDeclarations (); + + Range range; + if (!metadata.TryGetSecurityDeclarationRange (owner, out range) + || !MoveTo (Table.DeclSecurity, range.Start)) + return new Collection (); + + var security_declarations = new Collection ((int) range.Length); + + for (int i = 0; i < range.Length; i++) { + var action = (SecurityAction) ReadUInt16 (); + ReadMetadataToken (CodedIndex.HasDeclSecurity); + var signature = ReadBlobIndex (); + + security_declarations.Add (new SecurityDeclaration (action, signature, module)); + } + + metadata.RemoveSecurityDeclarationRange (owner); + + return security_declarations; + } + + public byte [] ReadSecurityDeclarationBlob (uint signature) + { + return ReadBlob (signature); + } + + public void ReadSecurityDeclarationSignature (SecurityDeclaration declaration) + { + var signature = declaration.signature; + var reader = ReadSignature (signature); + + if (reader.buffer [reader.position] != '.') { + ReadXmlSecurityDeclaration (signature, declaration); + return; + } + + reader.ReadByte (); + var count = reader.ReadCompressedUInt32 (); + var attributes = new Collection ((int) count); + + for (int i = 0; i < count; i++) + attributes.Add (reader.ReadSecurityAttribute ()); + + declaration.security_attributes = attributes; + } + + void ReadXmlSecurityDeclaration (uint signature, SecurityDeclaration declaration) + { + var blob = ReadBlob (signature); + var attributes = new Collection (1); + + var attribute = new SecurityAttribute ( + module.TypeSystem.LookupType ("System.Security.Permissions", "PermissionSetAttribute")); + + attribute.properties = new Collection (1); + attribute.properties.Add ( + new CustomAttributeNamedArgument ( + "XML", + new CustomAttributeArgument ( + module.TypeSystem.String, + Encoding.Unicode.GetString (blob, 0, blob.Length)))); + + attributes.Add (attribute); + + declaration.security_attributes = attributes; + } + + public Collection ReadExportedTypes () + { + var length = MoveTo (Table.ExportedType); + if (length == 0) + return new Collection (); + + var exported_types = new Collection (length); + + for (int i = 1; i <= length; i++) { + var attributes = (TypeAttributes) ReadUInt32 (); + var identifier = ReadUInt32 (); + var name = ReadString (); + var @namespace = ReadString (); + var implementation = ReadMetadataToken (CodedIndex.Implementation); + + ExportedType declaring_type = null; + IMetadataScope scope = null; + + switch (implementation.TokenType) { + case TokenType.AssemblyRef: + case TokenType.File: + scope = GetExportedTypeScope (implementation); + break; + case TokenType.ExportedType: + // FIXME: if the table is not properly sorted + declaring_type = exported_types [(int) implementation.RID - 1]; + break; + } + + var exported_type = new ExportedType (@namespace, name, module, scope) { + Attributes = attributes, + Identifier = (int) identifier, + DeclaringType = declaring_type, + }; + exported_type.token = new MetadataToken (TokenType.ExportedType, i); + + exported_types.Add (exported_type); + } + + return exported_types; + } + + IMetadataScope GetExportedTypeScope (MetadataToken token) + { + var position = this.position; + IMetadataScope scope; + + switch (token.TokenType) { + case TokenType.AssemblyRef: + InitializeAssemblyReferences (); + scope = metadata.AssemblyReferences [(int) token.RID - 1]; + break; + case TokenType.File: + scope = GetModuleReferenceFromFile (token); + if (scope == null) + throw new NotSupportedException (); + + break; + default: + throw new NotSupportedException (); + } + + this.position = position; + return scope; + } + + ModuleReference GetModuleReferenceFromFile (MetadataToken token) + { + if (!MoveTo (Table.File, token.RID)) + return null; + + ReadUInt32 (); + var file_name = ReadString (); + var modules = module.ModuleReferences; + + ModuleReference reference = null; + for (int i = 0; i < modules.Count; i++) { + var module_reference = modules [i]; + if (module_reference.Name != file_name) + continue; + + reference = module_reference; + break; + } + + return reference; + } + + static void InitializeCollection (object o) + { + } + } + + sealed class SignatureReader : ByteBuffer { + + readonly MetadataReader reader; + readonly uint start, sig_length; + + TypeSystem TypeSystem { + get { return reader.module.TypeSystem; } + } + + public SignatureReader (uint blob, MetadataReader reader) + : base (reader.buffer) + { + this.reader = reader; + + MoveToBlob (blob); + + this.sig_length = ReadCompressedUInt32 (); + this.start = (uint) position; + } + + void MoveToBlob (uint blob) + { + position = (int) (reader.image.BlobHeap.Offset + blob); + } + + MetadataToken ReadTypeTokenSignature () + { + return CodedIndex.TypeDefOrRef.GetMetadataToken (ReadCompressedUInt32 ()); + } + + GenericParameter GetGenericParameter (GenericParameterType type, uint var) + { + var context = reader.context; + + if (context == null) + throw new NotSupportedException (); + + IGenericParameterProvider provider; + + switch (type) { + case GenericParameterType.Type: + provider = context.Type; + break; + case GenericParameterType.Method: + provider = context.Method; + break; + default: + throw new NotSupportedException (); + } + + int index = (int) var; + + if (!context.IsDefinition) + CheckGenericContext (provider, index); + + return provider.GenericParameters [index]; + } + + static void CheckGenericContext (IGenericParameterProvider owner, int index) + { + var owner_parameters = owner.GenericParameters; + + for (int i = owner_parameters.Count; i <= index; i++) + owner_parameters.Add (new GenericParameter (owner)); + } + + public void ReadGenericInstanceSignature (IGenericParameterProvider provider, IGenericInstance instance) + { + var arity = ReadCompressedUInt32 (); + + if (!provider.IsDefinition) + CheckGenericContext (provider, (int) arity - 1); + + var instance_arguments = instance.GenericArguments; + + for (int i = 0; i < arity; i++) + instance_arguments.Add (ReadTypeSignature ()); + } + + ArrayType ReadArrayTypeSignature () + { + var array = new ArrayType (ReadTypeSignature ()); + + var rank = ReadCompressedUInt32 (); + + var sizes = new uint [ReadCompressedUInt32 ()]; + for (int i = 0; i < sizes.Length; i++) + sizes [i] = ReadCompressedUInt32 (); + + var low_bounds = new int [ReadCompressedUInt32 ()]; + for (int i = 0; i < low_bounds.Length; i++) + low_bounds [i] = ReadCompressedInt32 (); + + array.Dimensions.Clear (); + + for (int i = 0; i < rank; i++) { + int? lower = null, upper = null; + + if (i < low_bounds.Length) + lower = low_bounds [i]; + + if (i < sizes.Length) + upper = lower + (int) sizes [i] - 1; + + array.Dimensions.Add (new ArrayDimension (lower, upper)); + } + + return array; + } + + TypeReference GetTypeDefOrRef (MetadataToken token) + { + return reader.GetTypeDefOrRef (token); + } + + public TypeReference ReadTypeSignature () + { + return ReadTypeSignature ((ElementType) ReadByte ()); + } + + TypeReference ReadTypeSignature (ElementType etype) + { + switch (etype) { + case ElementType.ValueType: { + var value_type = GetTypeDefOrRef (ReadTypeTokenSignature ()); + value_type.IsValueType = true; + return value_type; + } + case ElementType.Class: + return GetTypeDefOrRef (ReadTypeTokenSignature ()); + case ElementType.Ptr: + return new PointerType (ReadTypeSignature ()); + case ElementType.FnPtr: { + var fptr = new FunctionPointerType (); + ReadMethodSignature (fptr); + return fptr; + } + case ElementType.ByRef: + return new ByReferenceType (ReadTypeSignature ()); + case ElementType.Pinned: + return new PinnedType (ReadTypeSignature ()); + case ElementType.SzArray: + return new ArrayType (ReadTypeSignature ()); + case ElementType.Array: + return ReadArrayTypeSignature (); + case ElementType.CModOpt: + return new OptionalModifierType ( + GetTypeDefOrRef (ReadTypeTokenSignature ()), ReadTypeSignature ()); + case ElementType.CModReqD: + return new RequiredModifierType ( + GetTypeDefOrRef (ReadTypeTokenSignature ()), ReadTypeSignature ()); + case ElementType.Sentinel: + return new SentinelType (ReadTypeSignature ()); + case ElementType.Var: + return GetGenericParameter (GenericParameterType.Type, ReadCompressedUInt32 ()); + case ElementType.MVar: + return GetGenericParameter (GenericParameterType.Method, ReadCompressedUInt32 ()); + case ElementType.GenericInst: { + var is_value_type = ReadByte () == (byte) ElementType.ValueType; + var element_type = GetTypeDefOrRef (ReadTypeTokenSignature ()); + var generic_instance = new GenericInstanceType (element_type); + + ReadGenericInstanceSignature (element_type, generic_instance); + + if (is_value_type) { + generic_instance.IsValueType = true; + element_type.GetElementType ().IsValueType = true; + } + + return generic_instance; + } + case ElementType.Object: return TypeSystem.Object; + case ElementType.Void: return TypeSystem.Void; + case ElementType.TypedByRef: return TypeSystem.TypedReference; + case ElementType.I: return TypeSystem.IntPtr; + case ElementType.U: return TypeSystem.UIntPtr; + default: return GetPrimitiveType (etype); + } + } + + public void ReadMethodSignature (IMethodSignature method) + { + var calling_convention = ReadByte (); + method.CallingConvention = (MethodCallingConvention) calling_convention; + method.HasThis = (calling_convention & 0x20) != 0; + method.ExplicitThis = (calling_convention & 0x40) != 0; + + var generic_context = method as MethodReference; + if (generic_context != null) + reader.context = generic_context; + + if ((calling_convention & 0x10) != 0) { + var arity = ReadCompressedUInt32 (); + + if (generic_context != null && !generic_context.IsDefinition) + CheckGenericContext (generic_context, (int) arity -1 ); + } + + // TODO: more call_conv + + var param_count = ReadCompressedUInt32 (); + + method.MethodReturnType.ReturnType = ReadTypeSignature (); + + if (param_count == 0) + return; + + Collection parameters; + + var method_ref = method as MethodReference; + if (method_ref != null) + parameters = method_ref.parameters = new ParameterDefinitionCollection (method, (int) param_count); + else + parameters = method.Parameters; + + for (int i = 0; i < param_count; i++) + parameters.Add (new ParameterDefinition (ReadTypeSignature ())); + } + + public object ReadConstantSignature (ElementType type) + { + return ReadPrimitiveValue (type); + } + + public void ReadCustomAttributeConstructorArguments (CustomAttribute attribute, Collection parameters) + { + var count = parameters.Count; + if (count == 0) + return; + + attribute.arguments = new Collection (count); + + for (int i = 0; i < count; i++) + attribute.arguments.Add ( + ReadCustomAttributeFixedArgument (parameters [i].ParameterType)); + } + + CustomAttributeArgument ReadCustomAttributeFixedArgument (TypeReference type) + { + if (type.IsArray) + return ReadCustomAttributeFixedArrayArgument ((ArrayType) type); + + return ReadCustomAttributeElement (type); + } + + public void ReadCustomAttributeNamedArguments (ushort count, ref Collection fields, ref Collection properties) + { + for (int i = 0; i < count; i++) + ReadCustomAttributeNamedArgument (ref fields, ref properties); + } + + void ReadCustomAttributeNamedArgument (ref Collection fields, ref Collection properties) + { + var kind = ReadByte (); + var type = ReadCustomAttributeFieldOrPropType (); + var name = ReadUTF8String (); + + Collection container; + switch (kind) { + case 0x53: + container = GetCustomAttributeNamedArgumentCollection (ref fields); + break; + case 0x54: + container = GetCustomAttributeNamedArgumentCollection (ref properties); + break; + default: + throw new NotSupportedException (); + } + + container.Add (new CustomAttributeNamedArgument (name, ReadCustomAttributeFixedArgument (type))); + } + + static Collection GetCustomAttributeNamedArgumentCollection (ref Collection collection) + { + if (collection != null) + return collection; + + return collection = new Collection (); + } + + CustomAttributeArgument ReadCustomAttributeFixedArrayArgument (ArrayType type) + { + var length = ReadUInt32 (); + + if (length == 0xffffffff) + return new CustomAttributeArgument (type, null); + + if (length == 0) + return new CustomAttributeArgument (type, Empty.Array); + + var arguments = new CustomAttributeArgument [length]; + var element_type = type.ElementType; + + for (int i = 0; i < length; i++) + arguments [i] = ReadCustomAttributeElement (element_type); + + return new CustomAttributeArgument (type, arguments); + } + + CustomAttributeArgument ReadCustomAttributeElement (TypeReference type) + { + if (type.IsArray) + return ReadCustomAttributeFixedArrayArgument ((ArrayType) type); + + return new CustomAttributeArgument ( + type, + type.etype == ElementType.Object + ? ReadCustomAttributeElement (ReadCustomAttributeFieldOrPropType ()) + : ReadCustomAttributeElementValue (type)); + } + + object ReadCustomAttributeElementValue (TypeReference type) + { + var etype = type.etype; + + switch (etype) { + case ElementType.String: + return ReadUTF8String (); + case ElementType.None: + if (type.IsTypeOf ("System", "Type")) + return ReadTypeReference (); + + return ReadCustomAttributeEnum (type); + default: + return ReadPrimitiveValue (etype); + } + } + + object ReadPrimitiveValue (ElementType type) + { + switch (type) { + case ElementType.Boolean: + return ReadByte () == 1; + case ElementType.I1: + return (sbyte) ReadByte (); + case ElementType.U1: + return ReadByte (); + case ElementType.Char: + return (char) ReadUInt16 (); + case ElementType.I2: + return ReadInt16 (); + case ElementType.U2: + return ReadUInt16 (); + case ElementType.I4: + return ReadInt32 (); + case ElementType.U4: + return ReadUInt32 (); + case ElementType.I8: + return ReadInt64 (); + case ElementType.U8: + return ReadUInt64 (); + case ElementType.R4: + return ReadSingle (); + case ElementType.R8: + return ReadDouble (); + default: + throw new NotImplementedException (type.ToString ()); + } + } + + TypeReference GetPrimitiveType (ElementType etype) + { + switch (etype) { + case ElementType.Boolean: + return TypeSystem.Boolean; + case ElementType.Char: + return TypeSystem.Char; + case ElementType.I1: + return TypeSystem.SByte; + case ElementType.U1: + return TypeSystem.Byte; + case ElementType.I2: + return TypeSystem.Int16; + case ElementType.U2: + return TypeSystem.UInt16; + case ElementType.I4: + return TypeSystem.Int32; + case ElementType.U4: + return TypeSystem.UInt32; + case ElementType.I8: + return TypeSystem.Int64; + case ElementType.U8: + return TypeSystem.UInt64; + case ElementType.R4: + return TypeSystem.Single; + case ElementType.R8: + return TypeSystem.Double; + case ElementType.String: + return TypeSystem.String; + default: + throw new NotImplementedException (etype.ToString ()); + } + } + + TypeReference ReadCustomAttributeFieldOrPropType () + { + var etype = (ElementType) ReadByte (); + + switch (etype) { + case ElementType.Boxed: + return TypeSystem.Object; + case ElementType.SzArray: + return new ArrayType (ReadCustomAttributeFieldOrPropType ()); + case ElementType.Enum: + return ReadTypeReference (); + case ElementType.Type: + return TypeSystem.LookupType ("System", "Type"); + default: + return GetPrimitiveType (etype); + } + } + + public TypeReference ReadTypeReference () + { + return TypeParser.ParseType (reader.module, ReadUTF8String ()); + } + + object ReadCustomAttributeEnum (TypeReference enum_type) + { + var type = enum_type.CheckedResolve (); + if (!type.IsEnum) + throw new ArgumentException (); + + return ReadCustomAttributeElementValue (type.GetEnumUnderlyingType ()); + } + + public SecurityAttribute ReadSecurityAttribute () + { + var attribute = new SecurityAttribute (ReadTypeReference ()); + + ReadCompressedUInt32 (); + + ReadCustomAttributeNamedArguments ( + (ushort) ReadCompressedUInt32 (), + ref attribute.fields, + ref attribute.properties); + + return attribute; + } + + public MarshalInfo ReadMarshalInfo () + { + var native = ReadNativeType (); + switch (native) { + case NativeType.Array: { + var array = new ArrayMarshalInfo (); + if (CanReadMore ()) + array.element_type = ReadNativeType (); + if (CanReadMore ()) + array.size_parameter_index = (int) ReadCompressedUInt32 (); + if (CanReadMore ()) + array.size = (int) ReadCompressedUInt32 (); + if (CanReadMore ()) + array.size_parameter_multiplier = (int) ReadCompressedUInt32 (); + return array; + } + case NativeType.SafeArray: { + var array = new SafeArrayMarshalInfo (); + if (CanReadMore ()) + array.element_type = ReadVariantType (); + return array; + } + case NativeType.FixedArray: { + var array = new FixedArrayMarshalInfo (); + if (CanReadMore ()) + array.size = (int) ReadCompressedUInt32 (); + if (CanReadMore ()) + array.element_type = ReadNativeType (); + return array; + } + case NativeType.FixedSysString: { + var sys_string = new FixedSysStringMarshalInfo (); + if (CanReadMore ()) + sys_string.size = (int) ReadCompressedUInt32 (); + return sys_string; + } + case NativeType.CustomMarshaler: { + var marshaler = new CustomMarshalInfo (); + var guid_value = ReadUTF8String (); + marshaler.guid = !string.IsNullOrEmpty (guid_value) ? new Guid (guid_value) : Guid.Empty; + marshaler.unmanaged_type = ReadUTF8String (); + marshaler.managed_type = ReadTypeReference (); + marshaler.cookie = ReadUTF8String (); + return marshaler; + } + default: + return new MarshalInfo (native); + } + } + + NativeType ReadNativeType () + { + return (NativeType) ReadByte (); + } + + VariantType ReadVariantType () + { + return (VariantType) ReadByte (); + } + + string ReadUTF8String () + { + if (buffer [position] == 0xff) { + position++; + return null; + } + + var length = (int) ReadCompressedUInt32 (); + if (length == 0) + return string.Empty; + + var @string = Encoding.UTF8.GetString (buffer, position, + buffer [position + length - 1] == 0 ? length - 1 : length); + + position += length; + return @string; + } + + public bool CanReadMore () + { + return position - start < sig_length; + } + } +} diff --git a/Mono.Cecil/AssemblyWriter.cs b/Mono.Cecil/AssemblyWriter.cs new file mode 100644 index 000000000..8dd914508 --- /dev/null +++ b/Mono.Cecil/AssemblyWriter.cs @@ -0,0 +1,2536 @@ +// +// AssemblyWriter.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +using Mono.Collections.Generic; +using Mono.Cecil.Cil; +using Mono.Cecil.Metadata; +using Mono.Cecil.PE; + +using RVA = System.UInt32; +using RID = System.UInt32; +using CodedRID = System.UInt32; +using StringIndex = System.UInt32; +using BlobIndex = System.UInt32; + +namespace Mono.Cecil { + +#if !READ_ONLY + + using TypeRefRow = Row; + using TypeDefRow = Row; + using FieldRow = Row; + using MethodRow = Row; + using ParamRow = Row; + using InterfaceImplRow = Row; + using MemberRefRow = Row; + using ConstantRow = Row; + using CustomAttributeRow = Row; + using FieldMarshalRow = Row; + using DeclSecurityRow = Row; + using ClassLayoutRow = Row; + using FieldLayoutRow = Row; + using EventMapRow = Row; + using EventRow = Row; + using PropertyMapRow = Row; + using PropertyRow = Row; + using MethodSemanticsRow = Row; + using MethodImplRow = Row; + using ImplMapRow = Row; + using FieldRVARow = Row; + using AssemblyRow = Row; + using AssemblyRefRow = Row; + using FileRow = Row; + using ExportedTypeRow = Row; + using ManifestResourceRow = Row; + using NestedClassRow = Row; + using GenericParamRow = Row; + using MethodSpecRow = Row; + using GenericParamConstraintRow = Row; + + static class ModuleWriter { + + public static void WriteModuleTo (ModuleDefinition module, Stream stream, WriterParameters parameters) + { + if ((module.Attributes & ModuleAttributes.ILOnly) == 0) + throw new ArgumentException (); + + if (module.HasImage && module.ReadingMode == ReadingMode.Deferred) + ImmediateModuleReader.ReadModule (module); + + module.MetadataSystem.Clear (); + + var name = module.assembly != null ? module.assembly.Name : null; + var fq_name = stream.GetFullyQualifiedName (); + var symbol_writer_provider = parameters.SymbolWriterProvider; + if (symbol_writer_provider == null && parameters.WriteSymbols) + symbol_writer_provider = SymbolProvider.GetPlatformWriterProvider (); + var symbol_writer = GetSymbolWriter (module, fq_name, symbol_writer_provider); + +#if !SILVERLIGHT && !CF + if (parameters.StrongNameKeyPair != null && name != null) + name.PublicKey = parameters.StrongNameKeyPair.PublicKey; +#endif + + if (name != null && name.HasPublicKey) + module.Attributes |= ModuleAttributes.StrongNameSigned; + + var metadata = new MetadataBuilder (module, fq_name, + symbol_writer_provider, symbol_writer); + + BuildMetadata (module, metadata); + + if (module.SymbolReader != null) + module.SymbolReader.Dispose (); + + var writer = ImageWriter.CreateWriter (module, metadata, stream); + + writer.WriteImage (); + +#if !SILVERLIGHT && !CF + if (parameters.StrongNameKeyPair != null) + CryptoService.StrongName (stream, writer, parameters.StrongNameKeyPair); +#endif + if (symbol_writer != null) + symbol_writer.Dispose (); + } + + static void BuildMetadata (ModuleDefinition module, MetadataBuilder metadata) + { + if (!module.HasImage) { + metadata.BuildMetadata (); + return; + } + + module.Read (metadata, (builder, _) => { + builder.BuildMetadata (); + return builder; + }); + } + + static ISymbolWriter GetSymbolWriter (ModuleDefinition module, string fq_name, ISymbolWriterProvider symbol_writer_provider) + { + if (symbol_writer_provider == null) + return null; + + return symbol_writer_provider.GetSymbolWriter (module, fq_name); + } + } + + abstract class MetadataTable { + + public abstract int Length { get; } + + public bool IsLarge { + get { return Length > 65535; } + } + + public abstract void Write (TableHeapBuffer buffer); + public abstract void Sort (); + } + + abstract class OneRowTable : MetadataTable where TRow : struct { + + internal TRow row; + + public sealed override int Length { + get { return 1; } + } + + public sealed override void Sort () + { + } + } + + abstract class MetadataTable : MetadataTable where TRow : struct { + + internal TRow [] rows = new TRow [2]; + internal int length; + + public sealed override int Length { + get { return length; } + } + + public int AddRow (TRow row) + { + if (rows.Length == length) + Grow (); + + rows [length++] = row; + return length; + } + + void Grow () + { + var rows = new TRow [this.rows.Length * 2]; + Array.Copy (this.rows, rows, this.rows.Length); + this.rows = rows; + } + + public override void Sort () + { + } + } + + abstract class SortedTable : MetadataTable, IComparer where TRow : struct { + + public sealed override void Sort () + { + Array.Sort (rows, 0, length, this); + } + + protected int Compare (uint x, uint y) + { + return x == y ? 0 : x > y ? 1 : -1; + } + + public abstract int Compare (TRow x, TRow y); + } + + sealed class ModuleTable : OneRowTable { + + public override void Write (TableHeapBuffer buffer) + { + buffer.WriteUInt16 (0); // Generation + buffer.WriteString (row); // Name + buffer.WriteUInt16 (1); // Mvid + buffer.WriteUInt16 (0); // EncId + buffer.WriteUInt16 (0); // EncBaseId + } + } + + sealed class TypeRefTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteCodedRID ( + rows [i].Col1, CodedIndex.ResolutionScope); // Scope + buffer.WriteString (rows [i].Col2); // Name + buffer.WriteString (rows [i].Col3); // Namespace + } + } + } + + sealed class TypeDefTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteUInt32 ((uint) rows [i].Col1); // Attributes + buffer.WriteString (rows [i].Col2); // Name + buffer.WriteString (rows [i].Col3); // Namespace + buffer.WriteCodedRID ( + rows [i].Col4, CodedIndex.TypeDefOrRef); // Extends + buffer.WriteRID (rows [i].Col5, Table.Field); // FieldList + buffer.WriteRID (rows [i].Col6, Table.Method); // MethodList + } + } + } + + sealed class FieldTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteUInt16 ((ushort) rows [i].Col1); // Attributes + buffer.WriteString (rows [i].Col2); // Name + buffer.WriteBlob (rows [i].Col3); // Signature + } + } + } + + sealed class MethodTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteUInt32 (rows [i].Col1); // RVA + buffer.WriteUInt16 ((ushort) rows [i].Col2); // ImplFlags + buffer.WriteUInt16 ((ushort) rows [i].Col3); // Flags + buffer.WriteString (rows [i].Col4); // Name + buffer.WriteBlob (rows [i].Col5); // Signature + buffer.WriteRID (rows [i].Col6, Table.Param); // ParamList + } + } + } + + sealed class ParamTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteUInt16 ((ushort) rows [i].Col1); // Attributes + buffer.WriteUInt16 (rows [i].Col2); // Sequence + buffer.WriteString (rows [i].Col3); // Name + } + } + } + + sealed class InterfaceImplTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteRID (rows [i].Col1, Table.TypeDef); // Class + buffer.WriteCodedRID (rows [i].Col2, CodedIndex.TypeDefOrRef); // Interface + } + } + + /*public override int Compare (InterfaceImplRow x, InterfaceImplRow y) + { + return (int) (x.Col1 == y.Col1 ? y.Col2 - x.Col2 : x.Col1 - y.Col1); + }*/ + } + + sealed class MemberRefTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteCodedRID (rows [i].Col1, CodedIndex.MemberRefParent); + buffer.WriteString (rows [i].Col2); + buffer.WriteBlob (rows [i].Col3); + } + } + } + + sealed class ConstantTable : SortedTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteUInt16 ((ushort) rows [i].Col1); + buffer.WriteCodedRID (rows [i].Col2, CodedIndex.HasConstant); + buffer.WriteBlob (rows [i].Col3); + } + } + + public override int Compare (ConstantRow x, ConstantRow y) + { + return Compare (x.Col2, y.Col2); + } + } + + sealed class CustomAttributeTable : SortedTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteCodedRID (rows [i].Col1, CodedIndex.HasCustomAttribute); // Parent + buffer.WriteCodedRID (rows [i].Col2, CodedIndex.CustomAttributeType); // Type + buffer.WriteBlob (rows [i].Col3); + } + } + + public override int Compare (CustomAttributeRow x, CustomAttributeRow y) + { + return Compare (x.Col1, y.Col1); + } + } + + sealed class FieldMarshalTable : SortedTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteCodedRID (rows [i].Col1, CodedIndex.HasFieldMarshal); + buffer.WriteBlob (rows [i].Col2); + } + } + + public override int Compare (FieldMarshalRow x, FieldMarshalRow y) + { + return Compare (x.Col1, y.Col1); + } + } + + sealed class DeclSecurityTable : SortedTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteUInt16 ((ushort) rows [i].Col1); + buffer.WriteCodedRID (rows [i].Col2, CodedIndex.HasDeclSecurity); + buffer.WriteBlob (rows [i].Col3); + } + } + + public override int Compare (DeclSecurityRow x, DeclSecurityRow y) + { + return Compare (x.Col2, y.Col2); + } + } + + sealed class ClassLayoutTable : SortedTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteUInt16 (rows [i].Col1); // PackingSize + buffer.WriteUInt32 (rows [i].Col2); // ClassSize + buffer.WriteRID (rows [i].Col3, Table.TypeDef); // Parent + } + } + + public override int Compare (ClassLayoutRow x, ClassLayoutRow y) + { + return Compare (x.Col3, y.Col3); + } + } + + sealed class FieldLayoutTable : SortedTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteUInt32 (rows [i].Col1); // Offset + buffer.WriteRID (rows [i].Col2, Table.Field); // Parent + } + } + + public override int Compare (FieldLayoutRow x, FieldLayoutRow y) + { + return Compare (x.Col2, y.Col2); + } + } + + sealed class StandAloneSigTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) + buffer.WriteBlob (rows [i]); + } + } + + sealed class EventMapTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteRID (rows [i].Col1, Table.TypeDef); // Parent + buffer.WriteRID (rows [i].Col2, Table.Event); // EventList + } + } + } + + sealed class EventTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteUInt16 ((ushort) rows [i].Col1); // Flags + buffer.WriteString (rows [i].Col2); // Name + buffer.WriteCodedRID (rows [i].Col3, CodedIndex.TypeDefOrRef); // EventType + } + } + } + + sealed class PropertyMapTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteRID (rows [i].Col1, Table.TypeDef); // Parent + buffer.WriteRID (rows [i].Col2, Table.Property); // PropertyList + } + } + } + + sealed class PropertyTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteUInt16 ((ushort) rows [i].Col1); // Flags + buffer.WriteString (rows [i].Col2); // Name + buffer.WriteBlob (rows [i].Col3); // Type + } + } + } + + sealed class MethodSemanticsTable : SortedTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteUInt16 ((ushort) rows [i].Col1); // Flags + buffer.WriteRID (rows [i].Col2, Table.Method); // Method + buffer.WriteCodedRID (rows [i].Col3, CodedIndex.HasSemantics); // Association + } + } + + public override int Compare (MethodSemanticsRow x, MethodSemanticsRow y) + { + return Compare (x.Col3, y.Col3); + } + } + + sealed class MethodImplTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteRID (rows [i].Col1, Table.TypeDef); // Class + buffer.WriteCodedRID (rows [i].Col2, CodedIndex.MethodDefOrRef); // MethodBody + buffer.WriteCodedRID (rows [i].Col3, CodedIndex.MethodDefOrRef); // MethodDeclaration + } + } + } + + sealed class ModuleRefTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) + buffer.WriteString (rows [i]); // Name + } + } + + sealed class TypeSpecTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) + buffer.WriteBlob (rows [i]); // Signature + } + } + + sealed class ImplMapTable : SortedTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteUInt16 ((ushort) rows [i].Col1); // Flags + buffer.WriteCodedRID (rows [i].Col2, CodedIndex.MemberForwarded); // MemberForwarded + buffer.WriteString (rows [i].Col3); // ImportName + buffer.WriteRID (rows [i].Col4, Table.ModuleRef); // ImportScope + } + } + + public override int Compare (ImplMapRow x, ImplMapRow y) + { + return Compare (x.Col2, y.Col2); + } + } + + sealed class FieldRVATable : SortedTable { + + internal int position; + + public override void Write (TableHeapBuffer buffer) + { + position = buffer.position; + for (int i = 0; i < length; i++) { + buffer.WriteUInt32 (rows [i].Col1); // RVA + buffer.WriteRID (rows [i].Col2, Table.Field); // Field + } + } + + public override int Compare (FieldRVARow x, FieldRVARow y) + { + return Compare (x.Col2, y.Col2); + } + } + + sealed class AssemblyTable : OneRowTable { + + public override void Write (TableHeapBuffer buffer) + { + buffer.WriteUInt32 ((uint) row.Col1); // AssemblyHashAlgorithm + buffer.WriteUInt16 (row.Col2); // MajorVersion + buffer.WriteUInt16 (row.Col3); // MinorVersion + buffer.WriteUInt16 (row.Col4); // Build + buffer.WriteUInt16 (row.Col5); // Revision + buffer.WriteUInt32 ((uint) row.Col6); // Flags + buffer.WriteBlob (row.Col7); // PublicKey + buffer.WriteString (row.Col8); // Name + buffer.WriteString (row.Col9); // Culture + } + } + + sealed class AssemblyRefTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteUInt16 (rows [i].Col1); // MajorVersion + buffer.WriteUInt16 (rows [i].Col2); // MinorVersion + buffer.WriteUInt16 (rows [i].Col3); // Build + buffer.WriteUInt16 (rows [i].Col4); // Revision + buffer.WriteUInt32 ((uint) rows [i].Col5); // Flags + buffer.WriteBlob (rows [i].Col6); // PublicKeyOrToken + buffer.WriteString (rows [i].Col7); // Name + buffer.WriteString (rows [i].Col8); // Culture + buffer.WriteBlob (rows [i].Col9); // Hash + } + } + } + + sealed class FileTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteUInt32 ((uint) rows [i].Col1); + buffer.WriteString (rows [i].Col2); + buffer.WriteBlob (rows [i].Col3); + } + } + } + + sealed class ExportedTypeTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteUInt32 ((uint) rows [i].Col1); + buffer.WriteUInt32 (rows [i].Col2); + buffer.WriteString (rows [i].Col3); + buffer.WriteString (rows [i].Col4); + buffer.WriteCodedRID (rows [i].Col5, CodedIndex.Implementation); + } + } + } + + sealed class ManifestResourceTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteUInt32 (rows [i].Col1); + buffer.WriteUInt32 ((uint) rows [i].Col2); + buffer.WriteString (rows [i].Col3); + buffer.WriteCodedRID (rows [i].Col4, CodedIndex.Implementation); + } + } + } + + sealed class NestedClassTable : SortedTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteRID (rows [i].Col1, Table.TypeDef); // NestedClass + buffer.WriteRID (rows [i].Col2, Table.TypeDef); // EnclosingClass + } + } + + public override int Compare (NestedClassRow x, NestedClassRow y) + { + return Compare (x.Col1, y.Col1); + } + } + + sealed class GenericParamTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteUInt16 (rows [i].Col1); // Number + buffer.WriteUInt16 ((ushort) rows [i].Col2); // Flags + buffer.WriteCodedRID (rows [i].Col3, CodedIndex.TypeOrMethodDef); // Owner + buffer.WriteString (rows [i].Col4); // Name + } + } + } + + sealed class MethodSpecTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteCodedRID (rows [i].Col1, CodedIndex.MethodDefOrRef); // Method + buffer.WriteBlob (rows [i].Col2); // Instantiation + } + } + } + + sealed class GenericParamConstraintTable : MetadataTable { + + public override void Write (TableHeapBuffer buffer) + { + for (int i = 0; i < length; i++) { + buffer.WriteRID (rows [i].Col1, Table.GenericParam); // Owner + buffer.WriteCodedRID (rows [i].Col2, CodedIndex.TypeDefOrRef); // Constraint + } + } + } + + sealed class MetadataBuilder { + + readonly internal ModuleDefinition module; + readonly internal ISymbolWriterProvider symbol_writer_provider; + readonly internal ISymbolWriter symbol_writer; + readonly internal TextMap text_map; + readonly internal string fq_name; + + readonly Dictionary type_ref_map; + readonly Dictionary type_spec_map; + readonly Dictionary member_ref_map; + readonly Dictionary method_spec_map; + readonly Collection generic_parameters; + readonly Dictionary method_def_map; + + readonly internal CodeWriter code; + readonly internal DataBuffer data; + readonly internal ResourceBuffer resources; + readonly internal StringHeapBuffer string_heap; + readonly internal UserStringHeapBuffer user_string_heap; + readonly internal BlobHeapBuffer blob_heap; + readonly internal TableHeapBuffer table_heap; + + internal MetadataToken entry_point; + + RID type_rid = 1; + RID field_rid = 1; + RID method_rid = 1; + RID param_rid = 1; + RID property_rid = 1; + RID event_rid = 1; + + readonly TypeRefTable type_ref_table; + readonly TypeDefTable type_def_table; + readonly FieldTable field_table; + readonly MethodTable method_table; + readonly ParamTable param_table; + readonly InterfaceImplTable iface_impl_table; + readonly MemberRefTable member_ref_table; + readonly ConstantTable constant_table; + readonly CustomAttributeTable custom_attribute_table; + readonly DeclSecurityTable declsec_table; + readonly StandAloneSigTable standalone_sig_table; + readonly EventMapTable event_map_table; + readonly EventTable event_table; + readonly PropertyMapTable property_map_table; + readonly PropertyTable property_table; + readonly TypeSpecTable typespec_table; + readonly MethodSpecTable method_spec_table; + + readonly internal bool write_symbols; + + public MetadataBuilder (ModuleDefinition module, string fq_name, ISymbolWriterProvider symbol_writer_provider, ISymbolWriter symbol_writer) + { + this.module = module; + this.text_map = CreateTextMap (); + this.fq_name = fq_name; + this.symbol_writer_provider = symbol_writer_provider; + this.symbol_writer = symbol_writer; + this.write_symbols = symbol_writer != null; + this.code = new CodeWriter (this); + this.data = new DataBuffer (); + this.resources = new ResourceBuffer (); + this.string_heap = new StringHeapBuffer (); + this.user_string_heap = new UserStringHeapBuffer (); + this.blob_heap = new BlobHeapBuffer (); + this.table_heap = new TableHeapBuffer (module, this); + + this.type_ref_table = GetTable (Table.TypeRef); + this.type_def_table = GetTable (Table.TypeDef); + this.field_table = GetTable (Table.Field); + this.method_table = GetTable (Table.Method); + this.param_table = GetTable (Table.Param); + this.iface_impl_table = GetTable (Table.InterfaceImpl); + this.member_ref_table = GetTable (Table.MemberRef); + this.constant_table = GetTable (Table.Constant); + this.custom_attribute_table = GetTable (Table.CustomAttribute); + this.declsec_table = GetTable (Table.DeclSecurity); + this.standalone_sig_table = GetTable (Table.StandAloneSig); + this.event_map_table = GetTable (Table.EventMap); + this.event_table = GetTable (Table.Event); + this.property_map_table = GetTable (Table.PropertyMap); + this.property_table = GetTable (Table.Property); + this.typespec_table = GetTable (Table.TypeSpec); + this.method_spec_table = GetTable (Table.MethodSpec); + + var row_equality_comparer = new RowEqualityComparer (); + type_ref_map = new Dictionary (row_equality_comparer); + type_spec_map = new Dictionary (); + member_ref_map = new Dictionary (row_equality_comparer); + method_spec_map = new Dictionary (row_equality_comparer); + generic_parameters = new Collection (); + if (write_symbols) + method_def_map = new Dictionary (); + } + + TextMap CreateTextMap () + { + var map = new TextMap (); + map.AddMap (TextSegment.ImportAddressTable, module.Architecture == TargetArchitecture.I386 ? 8 : 16); + map.AddMap (TextSegment.CLIHeader, 0x48, 8); + return map; + } + + TTable GetTable (Table table) where TTable : MetadataTable, new () + { + return table_heap.GetTable (table); + } + + uint GetStringIndex (string @string) + { + if (string.IsNullOrEmpty (@string)) + return 0; + + return string_heap.GetStringIndex (@string); + } + + uint GetBlobIndex (ByteBuffer blob) + { + if (blob.length == 0) + return 0; + + return blob_heap.GetBlobIndex (blob); + } + + uint GetBlobIndex (byte [] blob) + { + if (blob.IsNullOrEmpty ()) + return 0; + + return GetBlobIndex (new ByteBuffer (blob)); + } + + public void BuildMetadata () + { + BuildModule (); + + table_heap.WriteTableHeap (); + } + + void BuildModule () + { + var table = GetTable (Table.Module); + table.row = GetStringIndex (module.Name); + + var assembly = module.Assembly; + + if (assembly != null) + BuildAssembly (); + + if (module.HasAssemblyReferences) + AddAssemblyReferences (); + + if (module.HasModuleReferences) + AddModuleReferences (); + + if (module.HasResources) + AddResources (); + + if (module.HasExportedTypes) + AddExportedTypes (); + + BuildTypes (); + + if (assembly != null) { + if (assembly.HasCustomAttributes) + AddCustomAttributes (assembly); + + if (assembly.HasSecurityDeclarations) + AddSecurityDeclarations (assembly); + } + + if (module.HasCustomAttributes) + AddCustomAttributes (module); + + if (module.EntryPoint != null) + entry_point = LookupToken (module.EntryPoint); + } + + void BuildAssembly () + { + var assembly = module.Assembly; + var name = assembly.Name; + + var table = GetTable (Table.Assembly); + + table.row = new AssemblyRow ( + name.HashAlgorithm, + (ushort) name.Version.Major, + (ushort) name.Version.Minor, + (ushort) name.Version.Build, + (ushort) name.Version.Revision, + name.Attributes, + GetBlobIndex (name.PublicKey), + GetStringIndex (name.Name), + GetStringIndex (name.Culture)); + + if (assembly.Modules.Count > 1) + BuildModules (); + } + + void BuildModules () + { + var modules = this.module.Assembly.Modules; + var table = GetTable (Table.File); + + for (int i = 0; i < modules.Count; i++) { + var module = modules [i]; + if (module.IsMain) + continue; + + var parameters = new WriterParameters { + SymbolWriterProvider = symbol_writer_provider, + }; + + var file_name = GetModuleFileName (module.Name); + module.Write (file_name, parameters); + + var hash = CryptoService.ComputeHash (file_name); + + table.AddRow (new FileRow ( + FileAttributes.ContainsMetaData, + GetStringIndex (module.Name), + GetBlobIndex (hash))); + } + } + + string GetModuleFileName (string name) + { + if (string.IsNullOrEmpty (name)) + throw new NotSupportedException (); + + var path = Path.GetDirectoryName (fq_name); + return Path.Combine (path, name); + } + + void AddAssemblyReferences () + { + var references = module.AssemblyReferences; + var table = GetTable (Table.AssemblyRef); + + for (int i = 0; i < references.Count; i++) { + var reference = references [i]; + + var key_or_token = reference.PublicKey.IsNullOrEmpty () + ? reference.PublicKeyToken + : reference.PublicKey; + + var rid = table.AddRow (new AssemblyRefRow ( + (ushort) reference.Version.Major, + (ushort) reference.Version.Minor, + (ushort) reference.Version.Build, + (ushort) reference.Version.Revision, + reference.Attributes, + GetBlobIndex (key_or_token), + GetStringIndex (reference.Name), + GetStringIndex (reference.Culture), + GetBlobIndex (reference.Hash))); + + reference.token = new MetadataToken (TokenType.AssemblyRef, rid); + } + } + + void AddModuleReferences () + { + var references = module.ModuleReferences; + var table = GetTable (Table.ModuleRef); + + for (int i = 0; i < references.Count; i++) { + var reference = references [i]; + + reference.token = new MetadataToken ( + TokenType.ModuleRef, + table.AddRow (GetStringIndex (reference.Name))); + } + } + + void AddResources () + { + var resources = module.Resources; + var table = GetTable (Table.ManifestResource); + + for (int i = 0; i < resources.Count; i++) { + var resource = resources [i]; + + var row = new ManifestResourceRow ( + 0, + resource.Attributes, + GetStringIndex (resource.Name), + 0); + + switch (resource.ResourceType) { + case ResourceType.Embedded: + row.Col1 = AddEmbeddedResource ((EmbeddedResource) resource); + break; + case ResourceType.Linked: + row.Col4 = CodedIndex.Implementation.CompressMetadataToken ( + new MetadataToken ( + TokenType.File, + AddLinkedResource ((LinkedResource) resource))); + break; + case ResourceType.AssemblyLinked: + row.Col4 = CodedIndex.Implementation.CompressMetadataToken ( + ((AssemblyLinkedResource) resource).Assembly.MetadataToken); + break; + default: + throw new NotSupportedException (); + } + + table.AddRow (row); + } + } + + uint AddLinkedResource (LinkedResource resource) + { + var table = GetTable (Table.File); + + var hash = resource.Hash.IsNullOrEmpty () + ? CryptoService.ComputeHash (resource.File) + : resource.Hash; + + return (uint) table.AddRow (new FileRow ( + FileAttributes.ContainsNoMetaData, + GetStringIndex (resource.File), + GetBlobIndex (hash))); + } + + uint AddEmbeddedResource (EmbeddedResource resource) + { + return resources.AddResource (resource.GetResourceData ()); + } + + void AddExportedTypes () + { + var exported_types = module.ExportedTypes; + var table = GetTable (Table.ExportedType); + + for (int i = 0; i < exported_types.Count; i++) { + var exported_type = exported_types [i]; + + var rid = table.AddRow (new ExportedTypeRow ( + exported_type.Attributes, + (uint) exported_type.Identifier, + GetStringIndex (exported_type.Name), + GetStringIndex (exported_type.Namespace), + MakeCodedRID (GetExportedTypeScope (exported_type), CodedIndex.Implementation))); + + exported_type.token = new MetadataToken (TokenType.ExportedType, rid); + } + } + + MetadataToken GetExportedTypeScope (ExportedType exported_type) + { + if (exported_type.DeclaringType != null) + return exported_type.DeclaringType.MetadataToken; + + var scope = exported_type.Scope; + switch (scope.MetadataToken.TokenType) { + case TokenType.AssemblyRef: + return scope.MetadataToken; + case TokenType.ModuleRef: + var file_table = GetTable (Table.File); + for (int i = 0; i < file_table.length; i++) + if (file_table.rows [i].Col2 == GetStringIndex (scope.Name)) + return new MetadataToken (TokenType.File, i + 1); + + break; + } + + throw new NotSupportedException (); + } + + void BuildTypes () + { + if (!module.HasTypes) + return; + + AttachTokens (); + AddTypeDefs (); + AddGenericParameters (); + } + + void AttachTokens () + { + var types = module.Types; + + for (int i = 0; i < types.Count; i++) + AttachTypeDefToken (types [i]); + } + + void AttachTypeDefToken (TypeDefinition type) + { + type.token = new MetadataToken (TokenType.TypeDef, type_rid++); + type.fields_range.Start = field_rid; + type.methods_range.Start = method_rid; + + if (type.HasFields) + AttachFieldsDefToken (type); + + if (type.HasMethods) + AttachMethodsDefToken (type); + + if (type.HasNestedTypes) + AttachNestedTypesDefToken (type); + } + + void AttachNestedTypesDefToken (TypeDefinition type) + { + var nested_types = type.NestedTypes; + for (int i = 0; i < nested_types.Count; i++) + AttachTypeDefToken (nested_types [i]); + } + + void AttachFieldsDefToken (TypeDefinition type) + { + var fields = type.Fields; + type.fields_range.Length = (uint) fields.Count; + for (int i = 0; i < fields.Count; i++) + fields [i].token = new MetadataToken (TokenType.Field, field_rid++); + } + + void AttachMethodsDefToken (TypeDefinition type) + { + var methods = type.Methods; + type.methods_range.Length = (uint) methods.Count; + for (int i = 0; i < methods.Count; i++) { + var method = methods [i]; + var new_token = new MetadataToken (TokenType.Method, method_rid++); + + if (write_symbols && method.token != MetadataToken.Zero) + method_def_map.Add (new_token, method.token); + + method.token = new_token; + } + } + + public bool TryGetOriginalMethodToken (MetadataToken new_token, out MetadataToken original) + { + return method_def_map.TryGetValue (new_token, out original); + } + + MetadataToken GetTypeToken (TypeReference type) + { + if (type == null) + return MetadataToken.Zero; + + if (type.IsDefinition) + return type.token; + + if (type.IsTypeSpecification ()) + return GetTypeSpecToken (type); + + return GetTypeRefToken (type); + } + + MetadataToken GetTypeSpecToken (TypeReference type) + { + var row = GetBlobIndex (GetTypeSpecSignature (type)); + + MetadataToken token; + if (type_spec_map.TryGetValue (row, out token)) + return token; + + return AddTypeSpecification (type, row); + } + + MetadataToken AddTypeSpecification (TypeReference type, uint row) + { + type.token = new MetadataToken (TokenType.TypeSpec, typespec_table.AddRow (row)); + + var token = type.token; + type_spec_map.Add (row, token); + return token; + } + + MetadataToken GetTypeRefToken (TypeReference type) + { + var row = CreateTypeRefRow (type); + + MetadataToken token; + if (type_ref_map.TryGetValue (row, out token)) + return token; + + return AddTypeReference (type, row); + } + + TypeRefRow CreateTypeRefRow (TypeReference type) + { + var scope_token = type.IsNested + ? GetTypeRefToken (type.DeclaringType) + : type.Scope.MetadataToken; + + return new TypeRefRow ( + MakeCodedRID (scope_token, CodedIndex.ResolutionScope), + GetStringIndex (type.Name), + GetStringIndex (type.Namespace)); + } + + static CodedRID MakeCodedRID (IMetadataTokenProvider provider, CodedIndex index) + { + return MakeCodedRID (provider.MetadataToken, index); + } + + static CodedRID MakeCodedRID (MetadataToken token, CodedIndex index) + { + return index.CompressMetadataToken (token); + } + + MetadataToken AddTypeReference (TypeReference type, TypeRefRow row) + { + type.token = new MetadataToken (TokenType.TypeRef, type_ref_table.AddRow (row)); + + var token = type.token; + type_ref_map.Add (row, token); + return token; + } + + void AddTypeDefs () + { + var types = module.Types; + + for (int i = 0; i < types.Count; i++) + AddType (types [i]); + } + + void AddType (TypeDefinition type) + { + type_def_table.AddRow (new TypeDefRow ( + type.Attributes, + GetStringIndex (type.Name), + GetStringIndex (type.Namespace), + MakeCodedRID (GetTypeToken (type.BaseType), CodedIndex.TypeDefOrRef), + type.fields_range.Start, + type.methods_range.Start)); + + if (type.HasGenericParameters) + AddGenericParameters (type); + + if (type.HasInterfaces) + AddInterfaces (type); + + if (type.HasLayoutInfo) + AddLayoutInfo (type); + + if (type.HasFields) + AddFields (type); + + if (type.HasMethods) + AddMethods (type); + + if (type.HasProperties) + AddProperties (type); + + if (type.HasEvents) + AddEvents (type); + + if (type.HasCustomAttributes) + AddCustomAttributes (type); + + if (type.HasSecurityDeclarations) + AddSecurityDeclarations (type); + + if (type.HasNestedTypes) + AddNestedTypes (type); + } + + void AddGenericParameters (IGenericParameterProvider owner) + { + var parameters = owner.GenericParameters; + + for (int i = 0; i < parameters.Count; i++) + generic_parameters.Add (parameters [i]); + } + + sealed class GenericParameterComparer : IComparer { + + public int Compare (GenericParameter a, GenericParameter b) + { + var a_owner = MakeCodedRID (a.Owner, CodedIndex.TypeOrMethodDef); + var b_owner = MakeCodedRID (b.Owner, CodedIndex.TypeOrMethodDef); + if (a_owner == b_owner) { + var a_pos = a.Position; + var b_pos = b.Position; + return a_pos == b_pos ? 0 : a_pos > b_pos ? 1 : -1; + } + + return a_owner > b_owner ? 1 : -1; + } + } + + void AddGenericParameters () + { + var items = this.generic_parameters.items; + var size = this.generic_parameters.size; + Array.Sort (items, 0, size, new GenericParameterComparer ()); + + var generic_param_table = GetTable (Table.GenericParam); + var generic_param_constraint_table = GetTable (Table.GenericParamConstraint); + + for (int i = 0; i < size; i++) { + var generic_parameter = items [i]; + + var rid = generic_param_table.AddRow (new GenericParamRow ( + (ushort) generic_parameter.Position, + generic_parameter.Attributes, + MakeCodedRID (generic_parameter.Owner, CodedIndex.TypeOrMethodDef), + GetStringIndex (generic_parameter.Name))); + + generic_parameter.token = new MetadataToken (TokenType.GenericParam, rid); + + if (generic_parameter.HasConstraints) + AddConstraints (generic_parameter, generic_param_constraint_table); + + if (generic_parameter.HasCustomAttributes) + AddCustomAttributes (generic_parameter); + } + } + + void AddConstraints (GenericParameter generic_parameter, GenericParamConstraintTable table) + { + var constraints = generic_parameter.Constraints; + + var rid = generic_parameter.token.RID; + + for (int i = 0; i < constraints.Count; i++) + table.AddRow (new GenericParamConstraintRow ( + rid, + MakeCodedRID (GetTypeToken (constraints [i]), CodedIndex.TypeDefOrRef))); + } + + void AddInterfaces (TypeDefinition type) + { + var interfaces = type.Interfaces; + var type_rid = type.token.RID; + + for (int i = 0; i < interfaces.Count; i++) + iface_impl_table.AddRow (new InterfaceImplRow ( + type_rid, + MakeCodedRID (GetTypeToken (interfaces [i]), CodedIndex.TypeDefOrRef))); + } + + void AddLayoutInfo (TypeDefinition type) + { + var table = GetTable (Table.ClassLayout); + + table.AddRow (new ClassLayoutRow ( + (ushort) type.PackingSize, + (uint) type.ClassSize, + type.token.RID)); + } + + void AddNestedTypes (TypeDefinition type) + { + var nested_types = type.NestedTypes; + var nested_table = GetTable (Table.NestedClass); + + for (int i = 0; i < nested_types.Count; i++) { + var nested = nested_types [i]; + AddType (nested); + nested_table.AddRow (new NestedClassRow (nested.token.RID, type.token.RID)); + } + } + + void AddFields (TypeDefinition type) + { + var fields = type.Fields; + + for (int i = 0; i < fields.Count; i++) + AddField (fields [i]); + } + + void AddField (FieldDefinition field) + { + field_table.AddRow (new FieldRow ( + field.Attributes, + GetStringIndex (field.Name), + GetBlobIndex (GetFieldSignature (field)))); + + if (!field.InitialValue.IsNullOrEmpty ()) + AddFieldRVA (field); + + if (field.HasLayoutInfo) + AddFieldLayout (field); + + if (field.HasCustomAttributes) + AddCustomAttributes (field); + + if (field.HasConstant) + AddConstant (field, field.FieldType); + + if (field.HasMarshalInfo) + AddMarshalInfo (field); + } + + void AddFieldRVA (FieldDefinition field) + { + var table = GetTable (Table.FieldRVA); + table.AddRow (new FieldRVARow ( + data.AddData (field.InitialValue), + field.token.RID)); + } + + void AddFieldLayout (FieldDefinition field) + { + var table = GetTable (Table.FieldLayout); + table.AddRow (new FieldLayoutRow ((uint) field.Offset, field.token.RID)); + } + + void AddMethods (TypeDefinition type) + { + var methods = type.Methods; + + for (int i = 0; i < methods.Count; i++) + AddMethod (methods [i]); + } + + void AddMethod (MethodDefinition method) + { + method_table.AddRow (new MethodRow ( + method.HasBody ? code.WriteMethodBody (method) : 0, + method.ImplAttributes, + method.Attributes, + GetStringIndex (method.Name), + GetBlobIndex (GetMethodSignature (method)), + param_rid)); + + AddParameters (method); + + if (method.HasGenericParameters) + AddGenericParameters (method); + + if (method.IsPInvokeImpl) + AddPInvokeInfo (method); + + if (method.HasCustomAttributes) + AddCustomAttributes (method); + + if (method.HasSecurityDeclarations) + AddSecurityDeclarations (method); + + if (method.HasOverrides) + AddOverrides (method); + } + + void AddParameters (MethodDefinition method) + { + var return_parameter = method.MethodReturnType.parameter; + + if (return_parameter != null && RequiresParameterRow (return_parameter)) + AddParameter (0, return_parameter, param_table); + + if (!method.HasParameters) + return; + + var parameters = method.Parameters; + + for (int i = 0; i < parameters.Count; i++) { + var parameter = parameters [i]; + if (!RequiresParameterRow (parameter)) + continue; + + AddParameter ((ushort) (i + 1), parameter, param_table); + } + } + + void AddPInvokeInfo (MethodDefinition method) + { + var pinvoke = method.PInvokeInfo; + if (pinvoke == null) + throw new ArgumentException (); + + var table = GetTable (Table.ImplMap); + table.AddRow (new ImplMapRow ( + pinvoke.Attributes, + MakeCodedRID (method, CodedIndex.MemberForwarded), + GetStringIndex (pinvoke.EntryPoint), + pinvoke.Module.MetadataToken.RID)); + } + + void AddOverrides (MethodDefinition method) + { + var overrides = method.Overrides; + var table = GetTable (Table.MethodImpl); + + for (int i = 0; i < overrides.Count; i++) { + table.AddRow (new MethodImplRow ( + method.DeclaringType.token.RID, + MakeCodedRID (method, CodedIndex.MethodDefOrRef), + MakeCodedRID (LookupToken (overrides [i]), CodedIndex.MethodDefOrRef))); + } + } + + static bool RequiresParameterRow (ParameterDefinition parameter) + { + return !string.IsNullOrEmpty (parameter.Name) + || parameter.Attributes != ParameterAttributes.None + || parameter.HasMarshalInfo + || parameter.HasConstant + || parameter.HasCustomAttributes; + } + + void AddParameter (ushort sequence, ParameterDefinition parameter, ParamTable table) + { + table.AddRow (new ParamRow ( + parameter.Attributes, + sequence, + GetStringIndex (parameter.Name))); + + parameter.token = new MetadataToken (TokenType.Param, param_rid++); + + if (parameter.HasCustomAttributes) + AddCustomAttributes (parameter); + + if (parameter.HasConstant) + AddConstant (parameter, parameter.ParameterType); + + if (parameter.HasMarshalInfo) + AddMarshalInfo (parameter); + } + + void AddMarshalInfo (IMarshalInfoProvider owner) + { + var table = GetTable (Table.FieldMarshal); + + table.AddRow (new FieldMarshalRow ( + MakeCodedRID (owner, CodedIndex.HasFieldMarshal), + GetBlobIndex (GetMarshalInfoSignature (owner)))); + } + + void AddProperties (TypeDefinition type) + { + var properties = type.Properties; + + property_map_table.AddRow (new PropertyMapRow (type.token.RID, property_rid)); + + for (int i = 0; i < properties.Count; i++) + AddProperty (properties [i]); + } + + void AddProperty (PropertyDefinition property) + { + property_table.AddRow (new PropertyRow ( + property.Attributes, + GetStringIndex (property.Name), + GetBlobIndex (GetPropertySignature (property)))); + property.token = new MetadataToken (TokenType.Property, property_rid++); + + var method = property.GetMethod; + if (method != null) + AddSemantic (MethodSemanticsAttributes.Getter, property, method); + + method = property.SetMethod; + if (method != null) + AddSemantic (MethodSemanticsAttributes.Setter, property, method); + + if (property.HasOtherMethods) + AddOtherSemantic (property, property.OtherMethods); + + if (property.HasCustomAttributes) + AddCustomAttributes (property); + + if (property.HasConstant) + AddConstant (property, property.PropertyType); + } + + void AddOtherSemantic (IMetadataTokenProvider owner, Collection others) + { + for (int i = 0; i < others.Count; i++) + AddSemantic (MethodSemanticsAttributes.Other, owner, others [i]); + } + + void AddEvents (TypeDefinition type) + { + var events = type.Events; + + event_map_table.AddRow (new EventMapRow (type.token.RID, event_rid)); + + for (int i = 0; i < events.Count; i++) + AddEvent (events [i]); + } + + void AddEvent (EventDefinition @event) + { + event_table.AddRow (new EventRow ( + @event.Attributes, + GetStringIndex (@event.Name), + MakeCodedRID (GetTypeToken (@event.EventType), CodedIndex.TypeDefOrRef))); + @event.token = new MetadataToken (TokenType.Event, event_rid++); + + var method = @event.AddMethod; + if (method != null) + AddSemantic (MethodSemanticsAttributes.AddOn, @event, method); + + method = @event.InvokeMethod; + if (method != null) + AddSemantic (MethodSemanticsAttributes.Fire, @event, method); + + method = @event.RemoveMethod; + if (method != null) + AddSemantic (MethodSemanticsAttributes.RemoveOn, @event, method); + + if (@event.HasOtherMethods) + AddOtherSemantic (@event, @event.OtherMethods); + + if (@event.HasCustomAttributes) + AddCustomAttributes (@event); + } + + void AddSemantic (MethodSemanticsAttributes semantics, IMetadataTokenProvider provider, MethodDefinition method) + { + method.SemanticsAttributes = semantics; + var table = GetTable (Table.MethodSemantics); + + table.AddRow (new MethodSemanticsRow ( + semantics, + method.token.RID, + MakeCodedRID (provider, CodedIndex.HasSemantics))); + } + + void AddConstant (IConstantProvider owner, TypeReference type) + { + var constant = owner.Constant; + var etype = GetConstantType (type, constant); + + constant_table.AddRow (new ConstantRow ( + etype, + MakeCodedRID (owner.MetadataToken, CodedIndex.HasConstant), + GetBlobIndex (GetConstantSignature (etype, constant)))); + } + + static ElementType GetConstantType (TypeReference constant_type, object constant) + { + if (constant == null) + return ElementType.Class; + + var etype = constant_type.etype; + switch (etype) { + case ElementType.None: + var type = constant_type.CheckedResolve (); + if (type.IsEnum) + return GetConstantType (type.GetEnumUnderlyingType (), constant); + + return ElementType.Class; + case ElementType.String: + return ElementType.String; + case ElementType.Object: + return GetConstantType (constant.GetType ()); + case ElementType.Array: + case ElementType.SzArray: + case ElementType.MVar: + case ElementType.Var: + return ElementType.Class; + case ElementType.GenericInst: + case ElementType.CModOpt: + case ElementType.CModReqD: + case ElementType.ByRef: + case ElementType.Sentinel: + return GetConstantType (((TypeSpecification) constant_type).ElementType, constant); + case ElementType.Boolean: + case ElementType.Char: + case ElementType.I: + case ElementType.I1: + case ElementType.I2: + case ElementType.I4: + case ElementType.I8: + case ElementType.U: + case ElementType.U1: + case ElementType.U2: + case ElementType.U4: + case ElementType.U8: + case ElementType.R4: + case ElementType.R8: + return GetConstantType (constant.GetType ()); + default: + return etype; + } + } + + static ElementType GetConstantType (Type type) + { + switch (Type.GetTypeCode (type)) { + case TypeCode.Boolean: + return ElementType.Boolean; + case TypeCode.Byte: + return ElementType.U1; + case TypeCode.SByte: + return ElementType.I1; + case TypeCode.Char: + return ElementType.Char; + case TypeCode.Int16: + return ElementType.I2; + case TypeCode.UInt16: + return ElementType.U2; + case TypeCode.Int32: + return ElementType.I4; + case TypeCode.UInt32: + return ElementType.U4; + case TypeCode.Int64: + return ElementType.I8; + case TypeCode.UInt64: + return ElementType.U8; + case TypeCode.Single: + return ElementType.R4; + case TypeCode.Double: + return ElementType.R8; + case TypeCode.String: + return ElementType.String; + default: + throw new NotSupportedException (type.FullName); + } + } + + void AddCustomAttributes (ICustomAttributeProvider owner) + { + var custom_attributes = owner.CustomAttributes; + + for (int i = 0; i < custom_attributes.Count; i++) { + var attribute = custom_attributes [i]; + + custom_attribute_table.AddRow (new CustomAttributeRow ( + MakeCodedRID (owner, CodedIndex.HasCustomAttribute), + MakeCodedRID (LookupToken (attribute.Constructor), CodedIndex.CustomAttributeType), + GetBlobIndex (GetCustomAttributeSignature (attribute)))); + } + } + + void AddSecurityDeclarations (ISecurityDeclarationProvider owner) + { + var declarations = owner.SecurityDeclarations; + + for (int i = 0; i < declarations.Count; i++) { + var declaration = declarations [i]; + + declsec_table.AddRow (new DeclSecurityRow ( + declaration.Action, + MakeCodedRID (owner, CodedIndex.HasDeclSecurity), + GetBlobIndex (GetSecurityDeclarationSignature (declaration)))); + } + } + + MetadataToken GetMemberRefToken (MemberReference member) + { + var row = CreateMemberRefRow (member); + + MetadataToken token; + if (member_ref_map.TryGetValue (row, out token)) + return token; + + AddMemberReference (member, row); + + return member.token; + } + + MemberRefRow CreateMemberRefRow (MemberReference member) + { + return new MemberRefRow ( + MakeCodedRID (GetTypeToken (member.DeclaringType), CodedIndex.MemberRefParent), + GetStringIndex (member.Name), + GetBlobIndex (GetMemberRefSignature (member))); + } + + void AddMemberReference (MemberReference member, MemberRefRow row) + { + member.token = new MetadataToken (TokenType.MemberRef, member_ref_table.AddRow (row)); + member_ref_map.Add (row, member.token); + } + + MetadataToken GetMethodSpecToken (MethodSpecification method_spec) + { + var row = CreateMethodSpecRow (method_spec); + + MetadataToken token; + if (method_spec_map.TryGetValue (row, out token)) + return token; + + AddMethodSpecification (method_spec, row); + + return method_spec.token; + } + + void AddMethodSpecification (MethodSpecification method_spec, MethodSpecRow row) + { + method_spec.token = new MetadataToken (TokenType.MethodSpec, method_spec_table.AddRow (row)); + method_spec_map.Add (row, method_spec.token); + } + + MethodSpecRow CreateMethodSpecRow (MethodSpecification method_spec) + { + return new MethodSpecRow ( + MakeCodedRID (LookupToken (method_spec.ElementMethod), CodedIndex.MethodDefOrRef), + GetBlobIndex (GetMethodSpecSignature (method_spec))); + } + + SignatureWriter CreateSignatureWriter () + { + return new SignatureWriter (this); + } + + SignatureWriter GetMethodSpecSignature (MethodSpecification method_spec) + { + if (!method_spec.IsGenericInstance) + throw new NotSupportedException (); + + var generic_instance = (GenericInstanceMethod) method_spec; + + var signature = CreateSignatureWriter (); + signature.WriteByte (0x0a); + + signature.WriteGenericInstanceSignature (generic_instance); + + return signature; + } + + public uint AddStandAloneSignature (uint signature) + { + return (uint) standalone_sig_table.AddRow (signature); + } + + public uint GetLocalVariableBlobIndex (Collection variables) + { + return GetBlobIndex (GetVariablesSignature (variables)); + } + + public uint GetCallSiteBlobIndex (CallSite call_site) + { + return GetBlobIndex (GetMethodSignature (call_site)); + } + + SignatureWriter GetVariablesSignature (Collection variables) + { + var signature = CreateSignatureWriter (); + signature.WriteByte (0x7); + signature.WriteCompressedUInt32 ((uint) variables.Count); + for (int i = 0; i < variables.Count; i++) + signature.WriteTypeSignature (variables [i].VariableType); + return signature; + } + + SignatureWriter GetFieldSignature (FieldReference field) + { + var signature = CreateSignatureWriter (); + signature.WriteByte (0x6); + signature.WriteTypeSignature (field.FieldType); + return signature; + } + + SignatureWriter GetMethodSignature (IMethodSignature method) + { + var signature = CreateSignatureWriter (); + signature.WriteMethodSignature (method); + return signature; + } + + SignatureWriter GetMemberRefSignature (MemberReference member) + { + var field = member as FieldReference; + if (field != null) + return GetFieldSignature (field); + + var method = member as MethodReference; + if (method != null) + return GetMethodSignature (method); + + throw new NotSupportedException (); + } + + SignatureWriter GetPropertySignature (PropertyDefinition property) + { + var signature = CreateSignatureWriter (); + byte calling_convention = 0x8; + if (property.HasThis) + calling_convention |= 0x20; + + uint param_count = 0; + Collection parameters = null; + + if (property.HasParameters) { + parameters = property.Parameters; + param_count = (uint) parameters.Count; + } + + signature.WriteByte (calling_convention); + signature.WriteCompressedUInt32 (param_count); + signature.WriteTypeSignature (property.PropertyType); + + if (param_count == 0) + return signature; + + for (int i = 0; i < param_count; i++) + signature.WriteTypeSignature (parameters [i].ParameterType); + + return signature; + } + + SignatureWriter GetTypeSpecSignature (TypeReference type) + { + var signature = CreateSignatureWriter (); + signature.WriteTypeSignature (type); + return signature; + } + + SignatureWriter GetConstantSignature (ElementType type, object value) + { + var signature = CreateSignatureWriter (); + + switch (type) { + case ElementType.Array: + case ElementType.SzArray: + case ElementType.Class: + case ElementType.Object: + case ElementType.Var: + case ElementType.MVar: + signature.WriteInt32 (0); + break; + case ElementType.String: + signature.WriteConstantString ((string) value); + break; + default: + signature.WriteConstantPrimitive (value); + break; + } + + return signature; + } + + SignatureWriter GetCustomAttributeSignature (CustomAttribute attribute) + { + var signature = CreateSignatureWriter (); + if (!attribute.resolved) { + signature.WriteBytes (attribute.GetBlob ()); + return signature; + } + + signature.WriteUInt16 (0x0001); + + signature.WriteCustomAttributeConstructorArguments (attribute); + + signature.WriteCustomAttributeNamedArguments (attribute); + + return signature; + } + + SignatureWriter GetSecurityDeclarationSignature (SecurityDeclaration declaration) + { + var signature = CreateSignatureWriter (); + if (!declaration.resolved) { + signature.WriteBytes (declaration.GetBlob ()); + return signature; + } + + signature.WriteByte ((byte) '.'); + + var attributes = declaration.security_attributes; + if (attributes == null) + throw new NotSupportedException (); + + signature.WriteCompressedUInt32 ((uint) attributes.Count); + + for (int i = 0; i < attributes.Count; i++) + signature.WriteSecurityAttribute (attributes [i]); + + return signature; + } + + SignatureWriter GetMarshalInfoSignature (IMarshalInfoProvider owner) + { + var signature = CreateSignatureWriter (); + + signature.WriteMarshalInfo (owner.MarshalInfo); + + return signature; + } + + static Exception CreateForeignMemberException (MemberReference member) + { + return new ArgumentException (string.Format ("Member '{0}' is declared in another module and needs to be imported", member)); + } + + public MetadataToken LookupToken (IMetadataTokenProvider provider) + { + if (provider == null) + throw new ArgumentNullException (); + + var member = provider as MemberReference; + if (member == null || member.Module != module) + throw CreateForeignMemberException (member); + + var token = provider.MetadataToken; + + switch (token.TokenType) { + case TokenType.TypeDef: + case TokenType.Method: + case TokenType.Field: + case TokenType.Event: + case TokenType.Property: + return token; + case TokenType.TypeRef: + case TokenType.TypeSpec: + case TokenType.GenericParam: + return GetTypeToken ((TypeReference) provider); + case TokenType.MethodSpec: + return GetMethodSpecToken ((MethodSpecification) provider); + case TokenType.MemberRef: + return GetMemberRefToken (member); + default: + throw new NotSupportedException (); + } + } + } + + sealed class SignatureWriter : ByteBuffer { + + readonly MetadataBuilder metadata; + + public SignatureWriter (MetadataBuilder metadata) + : base (6) + { + this.metadata = metadata; + } + + public void WriteElementType (ElementType element_type) + { + WriteByte ((byte) element_type); + } + + public void WriteUTF8String (string @string) + { + if (@string == null) { + WriteByte (0xff); + return; + } + + var bytes = Encoding.UTF8.GetBytes (@string); + WriteCompressedUInt32 ((uint) bytes.Length); + WriteBytes (bytes); + } + + public void WriteMethodSignature (IMethodSignature method) + { + byte calling_convention = (byte) method.CallingConvention; + if (method.HasThis) + calling_convention |= 0x20; + if (method.ExplicitThis) + calling_convention |= 0x40; + + var generic_provider = method as IGenericParameterProvider; + var generic_arity = generic_provider != null && generic_provider.HasGenericParameters + ? generic_provider.GenericParameters.Count + : 0; + + if (generic_arity > 0) + calling_convention |= 0x10; + + var param_count = method.HasParameters ? method.Parameters.Count : 0; + + WriteByte (calling_convention); + + if (generic_arity > 0) + WriteCompressedUInt32 ((uint) generic_arity); + + WriteCompressedUInt32 ((uint) param_count); + WriteTypeSignature (method.ReturnType); + + if (param_count == 0) + return; + + var parameters = method.Parameters; + + for (int i = 0; i < param_count; i++) + WriteTypeSignature (parameters [i].ParameterType); + } + + uint MakeTypeDefOrRefCodedRID (TypeReference type) + { + return CodedIndex.TypeDefOrRef.CompressMetadataToken (metadata.LookupToken (type)); + } + + public void WriteTypeSignature (TypeReference type) + { + if (type == null) + throw new ArgumentNullException (); + + var etype = type.etype; + + switch (etype) { + case ElementType.MVar: + case ElementType.Var: { + var generic_parameter = (GenericParameter) type; + + WriteElementType (etype); + var position = generic_parameter.Position; + if (position == -1) + throw new NotSupportedException (); + + WriteCompressedUInt32 ((uint) position); + break; + } + + case ElementType.GenericInst: { + var generic_instance = (GenericInstanceType) type; + WriteElementType (ElementType.GenericInst); + WriteElementType (generic_instance.IsValueType ? ElementType.ValueType : ElementType.Class); + WriteCompressedUInt32 (MakeTypeDefOrRefCodedRID (generic_instance.ElementType)); + + WriteGenericInstanceSignature (generic_instance); + break; + } + + case ElementType.Ptr: + case ElementType.ByRef: + case ElementType.Pinned: + case ElementType.Sentinel: { + var type_spec = (TypeSpecification) type; + WriteElementType (etype); + WriteTypeSignature (type_spec.ElementType); + break; + } + + case ElementType.FnPtr: { + var fptr = (FunctionPointerType) type; + WriteElementType (ElementType.FnPtr); + WriteMethodSignature (fptr); + break; + } + + case ElementType.CModOpt: + case ElementType.CModReqD: { + var modifier = (IModifierType) type; + WriteModifierSignature (etype, modifier); + break; + } + + case ElementType.Array: { + var array = (ArrayType) type; + if (!array.IsVector) { + WriteArrayTypeSignature (array); + break; + } + + WriteElementType (ElementType.SzArray); + WriteTypeSignature (array.ElementType); + break; + } + + case ElementType.None: { + WriteElementType (type.IsValueType ? ElementType.ValueType : ElementType.Class); + WriteCompressedUInt32 (MakeTypeDefOrRefCodedRID (type)); + break; + } + + default: + if (!TryWriteElementType (type)) + throw new NotSupportedException (); + + break; + + } + } + + void WriteArrayTypeSignature (ArrayType array) + { + WriteElementType (ElementType.Array); + WriteTypeSignature (array.ElementType); + + var dimensions = array.Dimensions; + var rank = dimensions.Count; + + WriteCompressedUInt32 ((uint) rank); + + var sized = 0; + var lbounds = 0; + + for (int i = 0; i < rank; i++) { + var dimension = dimensions [i]; + + if (dimension.UpperBound.HasValue) { + sized++; + lbounds++; + } else if (dimension.LowerBound.HasValue) + lbounds++; + } + + var sizes = new int [sized]; + var low_bounds = new int [lbounds]; + + for (int i = 0; i < lbounds; i++) { + var dimension = dimensions [i]; + low_bounds [i] = dimension.LowerBound.GetValueOrDefault (); + if (dimension.UpperBound.HasValue) + sizes [i] = dimension.UpperBound.Value - low_bounds [i] + 1; + } + + WriteCompressedUInt32 ((uint) sized); + for (int i = 0; i < sized; i++) + WriteCompressedUInt32 ((uint) sizes [i]); + + WriteCompressedUInt32 ((uint) lbounds); + for (int i = 0; i < lbounds; i++) + WriteCompressedInt32 (low_bounds [i]); + } + + public void WriteGenericInstanceSignature (IGenericInstance instance) + { + var generic_arguments = instance.GenericArguments; + var arity = generic_arguments.Count; + + WriteCompressedUInt32 ((uint) arity); + for (int i = 0; i < arity; i++) + WriteTypeSignature (generic_arguments [i]); + } + + void WriteModifierSignature (ElementType element_type, IModifierType type) + { + WriteElementType (element_type); + WriteCompressedUInt32 (MakeTypeDefOrRefCodedRID (type.ModifierType)); + WriteTypeSignature (type.ElementType); + } + + bool TryWriteElementType (TypeReference type) + { + var element = type.etype; + + if (element == ElementType.None) + return false; + + WriteElementType (element); + return true; + } + + public void WriteConstantString (string value) + { + WriteBytes (Encoding.Unicode.GetBytes (value)); + } + + public void WriteConstantPrimitive (object value) + { + WritePrimitiveValue (value); + } + + public void WriteCustomAttributeConstructorArguments (CustomAttribute attribute) + { + if (!attribute.HasConstructorArguments) + return; + + var arguments = attribute.ConstructorArguments; + var parameters = attribute.Constructor.Parameters; + + if (parameters.Count != arguments.Count) + throw new InvalidOperationException (); + + for (int i = 0; i < arguments.Count; i++) + WriteCustomAttributeFixedArgument (parameters [i].ParameterType, arguments [i]); + } + + void WriteCustomAttributeFixedArgument (TypeReference type, CustomAttributeArgument argument) + { + if (type.IsArray) { + WriteCustomAttributeFixedArrayArgument ((ArrayType) type, argument); + return; + } + + WriteCustomAttributeElement (type, argument); + } + + void WriteCustomAttributeFixedArrayArgument (ArrayType type, CustomAttributeArgument argument) + { + var values = argument.Value as CustomAttributeArgument []; + + if (values == null) { + WriteUInt32 (0xffffffff); + return; + } + + WriteInt32 (values.Length); + + if (values.Length == 0) + return; + + var element_type = type.ElementType; + + for (int i = 0; i < values.Length; i++) + WriteCustomAttributeElement (element_type, values [i]); + } + + void WriteCustomAttributeElement (TypeReference type, CustomAttributeArgument argument) + { + if (type.IsArray) { + WriteCustomAttributeFixedArrayArgument ((ArrayType) type, argument); + return; + } + + if (type.etype == ElementType.Object) { + argument = (CustomAttributeArgument) argument.Value; + type = argument.Type; + + WriteCustomAttributeFieldOrPropType (type); + WriteCustomAttributeElement (type, argument); + return; + } + + WriteCustomAttributeValue (type, argument.Value); + } + + void WriteCustomAttributeValue (TypeReference type, object value) + { + var etype = type.etype; + + switch (etype) { + case ElementType.String: + var @string = (string) value; + if (@string == null) + WriteByte (0xff); + else + WriteUTF8String (@string); + break; + case ElementType.None: + if (type.IsTypeOf ("System", "Type")) + WriteTypeReference ((TypeReference) value); + else + WriteCustomAttributeEnumValue (type, value); + break; + default: + WritePrimitiveValue (value); + break; + } + } + + void WritePrimitiveValue (object value) + { + if (value == null) + throw new ArgumentNullException (); + + switch (Type.GetTypeCode (value.GetType ())) { + case TypeCode.Boolean: + WriteByte ((byte) (((bool) value) ? 1 : 0)); + break; + case TypeCode.Byte: + WriteByte ((byte) value); + break; + case TypeCode.SByte: + WriteSByte ((sbyte) value); + break; + case TypeCode.Int16: + WriteInt16 ((short) value); + break; + case TypeCode.UInt16: + WriteUInt16 ((ushort) value); + break; + case TypeCode.Char: + WriteInt16 ((short) (char) value); + break; + case TypeCode.Int32: + WriteInt32 ((int) value); + break; + case TypeCode.UInt32: + WriteUInt32 ((uint) value); + break; + case TypeCode.Single: + WriteSingle ((float) value); + break; + case TypeCode.Int64: + WriteInt64 ((long) value); + break; + case TypeCode.UInt64: + WriteUInt64 ((ulong) value); + break; + case TypeCode.Double: + WriteDouble ((double) value); + break; + default: + throw new NotSupportedException (value.GetType ().FullName); + } + } + + void WriteCustomAttributeEnumValue (TypeReference enum_type, object value) + { + var type = enum_type.CheckedResolve (); + if (!type.IsEnum) + throw new ArgumentException (); + + WriteCustomAttributeValue (type.GetEnumUnderlyingType (), value); + } + + void WriteCustomAttributeFieldOrPropType (TypeReference type) + { + if (type.IsArray) { + var array = (ArrayType) type; + WriteElementType (ElementType.SzArray); + WriteCustomAttributeFieldOrPropType (array.ElementType); + return; + } + + var etype = type.etype; + + switch (etype) { + case ElementType.Object: + WriteElementType (ElementType.Boxed); + return; + case ElementType.None: + if (type.IsTypeOf ("System", "Type")) + WriteElementType (ElementType.Type); + else { + WriteElementType (ElementType.Enum); + WriteTypeReference (type); + } + return; + default: + WriteElementType (etype); + return; + } + } + + public void WriteCustomAttributeNamedArguments (CustomAttribute attribute) + { + var count = GetNamedArgumentCount (attribute); + + WriteUInt16 ((ushort) count); + + if (count == 0) + return; + + WriteICustomAttributeNamedArguments (attribute); + } + + static int GetNamedArgumentCount (ICustomAttribute attribute) + { + int count = 0; + + if (attribute.HasFields) + count += attribute.Fields.Count; + + if (attribute.HasProperties) + count += attribute.Properties.Count; + + return count; + } + + void WriteICustomAttributeNamedArguments (ICustomAttribute attribute) + { + if (attribute.HasFields) + WriteCustomAttributeNamedArguments (0x53, attribute.Fields); + + if (attribute.HasProperties) + WriteCustomAttributeNamedArguments (0x54, attribute.Properties); + } + + void WriteCustomAttributeNamedArguments (byte kind, Collection named_arguments) + { + for (int i = 0; i < named_arguments.Count; i++) + WriteCustomAttributeNamedArgument (kind, named_arguments [i]); + } + + void WriteCustomAttributeNamedArgument (byte kind, CustomAttributeNamedArgument named_argument) + { + var argument = named_argument.Argument; + + WriteByte (kind); + WriteCustomAttributeFieldOrPropType (argument.Type); + WriteUTF8String (named_argument.Name); + WriteCustomAttributeFixedArgument (argument.Type, argument); + } + + public void WriteSecurityAttribute (SecurityAttribute attribute) + { + WriteTypeReference (attribute.AttributeType); + + var count = GetNamedArgumentCount (attribute); + + if (count == 0) { + WriteCompressedUInt32 (0); // length + WriteCompressedUInt32 (0); // count + return; + } + + var buffer = new SignatureWriter (metadata); + buffer.WriteCompressedUInt32 ((uint) count); + buffer.WriteICustomAttributeNamedArguments (attribute); + + WriteCompressedUInt32 ((uint) buffer.length); + WriteBytes (buffer); + } + + void WriteTypeReference (TypeReference type) + { + WriteUTF8String (TypeParser.ToParseable (type)); + } + + public void WriteMarshalInfo (MarshalInfo marshal_info) + { + WriteNativeType (marshal_info.native); + + switch (marshal_info.native) { + case NativeType.Array: { + var array = (ArrayMarshalInfo) marshal_info; + if (array.element_type != NativeType.None) + WriteNativeType (array.element_type); + if (array.size_parameter_index > -1) + WriteCompressedUInt32 ((uint) array.size_parameter_index); + if (array.size > -1) + WriteCompressedUInt32 ((uint) array.size); + if (array.size_parameter_multiplier > -1) + WriteCompressedUInt32 ((uint) array.size_parameter_multiplier); + return; + } + case NativeType.SafeArray: { + var array = (SafeArrayMarshalInfo) marshal_info; + if (array.element_type != VariantType.None) + WriteVariantType (array.element_type); + return; + } + case NativeType.FixedArray: { + var array = (FixedArrayMarshalInfo) marshal_info; + if (array.size > -1) + WriteCompressedUInt32 ((uint) array.size); + if (array.element_type != NativeType.None) + WriteNativeType (array.element_type); + return; + } + case NativeType.FixedSysString: + var sys_string = (FixedSysStringMarshalInfo) marshal_info; + if (sys_string.size > -1) + WriteCompressedUInt32 ((uint) sys_string.size); + return; + case NativeType.CustomMarshaler: + var marshaler = (CustomMarshalInfo) marshal_info; + WriteUTF8String (marshaler.guid != Guid.Empty ? marshaler.guid.ToString () : string.Empty); + WriteUTF8String (marshaler.unmanaged_type); + WriteTypeReference (marshaler.managed_type); + WriteUTF8String (marshaler.cookie); + return; + } + } + + void WriteNativeType (NativeType native) + { + WriteByte ((byte) native); + } + + void WriteVariantType (VariantType variant) + { + WriteByte ((byte) variant); + } + } + +#endif + +} diff --git a/Mono.Cecil/BaseAssemblyResolver.cs b/Mono.Cecil/BaseAssemblyResolver.cs new file mode 100644 index 000000000..20b5fbe98 --- /dev/null +++ b/Mono.Cecil/BaseAssemblyResolver.cs @@ -0,0 +1,336 @@ +// +// BaseAssemblyResolver.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +using Mono.Collections.Generic; + +namespace Mono.Cecil { + + public delegate AssemblyDefinition AssemblyResolveEventHandler (object sender, AssemblyNameReference reference); + + public sealed class AssemblyResolveEventArgs : EventArgs { + + readonly AssemblyNameReference reference; + + public AssemblyNameReference AssemblyReference { + get { return reference; } + } + + public AssemblyResolveEventArgs (AssemblyNameReference reference) + { + this.reference = reference; + } + } + + public abstract class BaseAssemblyResolver : IAssemblyResolver { + + static readonly bool on_mono = Type.GetType ("Mono.Runtime") != null; + + readonly Collection directories; + +#if !SILVERLIGHT && !CF + Collection gac_paths; +#endif + + public void AddSearchDirectory (string directory) + { + directories.Add (directory); + } + + public void RemoveSearchDirectory (string directory) + { + directories.Remove (directory); + } + + public string [] GetSearchDirectories () + { + var directories = new string [this.directories.size]; + Array.Copy (this.directories.items, directories, directories.Length); + return directories; + } + + public virtual AssemblyDefinition Resolve (string fullName) + { + return Resolve (fullName, new ReaderParameters ()); + } + + public virtual AssemblyDefinition Resolve (string fullName, ReaderParameters parameters) + { + if (fullName == null) + throw new ArgumentNullException ("fullName"); + + return Resolve (AssemblyNameReference.Parse (fullName), parameters); + } + + public event AssemblyResolveEventHandler ResolveFailure; + + protected BaseAssemblyResolver () + { + directories = new Collection (2) { ".", "bin" }; + } + + AssemblyDefinition GetAssembly (string file, ReaderParameters parameters) + { + if (parameters.AssemblyResolver == null) + parameters.AssemblyResolver = this; + + return ModuleDefinition.ReadModule (file, parameters).Assembly; + } + + public virtual AssemblyDefinition Resolve (AssemblyNameReference name) + { + return Resolve (name, new ReaderParameters ()); + } + + public virtual AssemblyDefinition Resolve (AssemblyNameReference name, ReaderParameters parameters) + { + if (name == null) + throw new ArgumentNullException ("name"); + if (parameters == null) + parameters = new ReaderParameters (); + + var assembly = SearchDirectory (name, directories, parameters); + if (assembly != null) + return assembly; + +#if !SILVERLIGHT && !CF + var framework_dir = Path.GetDirectoryName (typeof (object).Module.FullyQualifiedName); + + if (IsZero (name.Version)) { + assembly = SearchDirectory (name, new [] { framework_dir }, parameters); + if (assembly != null) + return assembly; + } + + if (name.Name == "mscorlib") { + assembly = GetCorlib (name, parameters); + if (assembly != null) + return assembly; + } + + assembly = GetAssemblyInGac (name, parameters); + if (assembly != null) + return assembly; + + assembly = SearchDirectory (name, new [] { framework_dir }, parameters); + if (assembly != null) + return assembly; +#endif + + if (ResolveFailure != null) { + assembly = ResolveFailure (this, name); + if (assembly != null) + return assembly; + } + + throw new FileNotFoundException ("Could not resolve: " + name); + } + + AssemblyDefinition SearchDirectory (AssemblyNameReference name, IEnumerable directories, ReaderParameters parameters) + { + var extensions = new [] { ".exe", ".dll" }; + foreach (var directory in directories) { + foreach (var extension in extensions) { + string file = Path.Combine (directory, name.Name + extension); + if (File.Exists (file)) + return GetAssembly (file, parameters); + } + } + + return null; + } + + static bool IsZero (Version version) + { + return version == null || (version.Major == 0 && version.Minor == 0 && version.Build == 0 && version.Revision == 0); + } + +#if !SILVERLIGHT && !CF + AssemblyDefinition GetCorlib (AssemblyNameReference reference, ReaderParameters parameters) + { + var version = reference.Version; + var corlib = typeof (object).Assembly.GetName (); + + if (corlib.Version == version || IsZero (version)) + return GetAssembly (typeof (object).Module.FullyQualifiedName, parameters); + + var path = Directory.GetParent ( + Directory.GetParent ( + typeof (object).Module.FullyQualifiedName).FullName + ).FullName; + + if (on_mono) { + if (version.Major == 1) + path = Path.Combine (path, "1.0"); + else if (version.Major == 2) { + if (version.MajorRevision == 5) + path = Path.Combine (path, "2.1"); + else + path = Path.Combine (path, "2.0"); + } else if (version.Major == 4) + path = Path.Combine (path, "4.0"); + else + throw new NotSupportedException ("Version not supported: " + version); + } else { + switch (version.Major) { + case 1: + if (version.MajorRevision == 3300) + path = Path.Combine (path, "v1.0.3705"); + else + path = Path.Combine (path, "v1.0.5000.0"); + break; + case 2: + path = Path.Combine (path, "v2.0.50727"); + break; + case 4: + path = Path.Combine (path, "v4.0.30319"); + break; + default: + throw new NotSupportedException ("Version not supported: " + version); + } + } + + var file = Path.Combine (path, "mscorlib.dll"); + if (File.Exists (file)) + return GetAssembly (file, parameters); + + return null; + } + + static Collection GetGacPaths () + { + if (on_mono) + return GetDefaultMonoGacPaths (); + + var paths = new Collection (2); + var windir = Environment.GetEnvironmentVariable ("WINDIR"); + if (windir == null) + return paths; + + paths.Add (Path.Combine (windir, "assembly")); + paths.Add (Path.Combine (windir, Path.Combine ("Microsoft.NET", "assembly"))); + return paths; + } + + static Collection GetDefaultMonoGacPaths () + { + var paths = new Collection (1); + var gac = GetCurrentMonoGac (); + if (gac != null) + paths.Add (gac); + + var gac_paths_env = Environment.GetEnvironmentVariable ("MONO_GAC_PREFIX"); + if (string.IsNullOrEmpty (gac_paths_env)) + return paths; + + var prefixes = gac_paths_env.Split (Path.PathSeparator); + foreach (var prefix in prefixes) { + if (string.IsNullOrEmpty (prefix)) + continue; + + var gac_path = Path.Combine (Path.Combine (Path.Combine (prefix, "lib"), "mono"), "gac"); + if (Directory.Exists (gac_path) && !paths.Contains (gac)) + paths.Add (gac_path); + } + + return paths; + } + + static string GetCurrentMonoGac () + { + return Path.Combine ( + Directory.GetParent ( + Path.GetDirectoryName (typeof (object).Module.FullyQualifiedName)).FullName, + "gac"); + } + + AssemblyDefinition GetAssemblyInGac (AssemblyNameReference reference, ReaderParameters parameters) + { + if (reference.PublicKeyToken == null || reference.PublicKeyToken.Length == 0) + return null; + + if (gac_paths == null) + gac_paths = GetGacPaths (); + + if (on_mono) + return GetAssemblyInMonoGac (reference, parameters); + + return GetAssemblyInNetGac (reference, parameters); + } + + AssemblyDefinition GetAssemblyInMonoGac (AssemblyNameReference reference, ReaderParameters parameters) + { + for (int i = 0; i < gac_paths.Count; i++) { + var gac_path = gac_paths [i]; + var file = GetAssemblyFile (reference, string.Empty, gac_path); + if (File.Exists (file)) + return GetAssembly (file, parameters); + } + + return null; + } + + AssemblyDefinition GetAssemblyInNetGac (AssemblyNameReference reference, ReaderParameters parameters) + { + var gacs = new [] { "GAC_MSIL", "GAC_32", "GAC" }; + var prefixes = new [] { string.Empty, "v4.0_" }; + + for (int i = 0; i < 2; i++) { + for (int j = 0; j < gacs.Length; j++) { + var gac = Path.Combine (gac_paths [i], gacs [j]); + var file = GetAssemblyFile (reference, prefixes [i], gac); + if (Directory.Exists (gac) && File.Exists (file)) + return GetAssembly (file, parameters); + } + } + + return null; + } + + static string GetAssemblyFile (AssemblyNameReference reference, string prefix, string gac) + { + var gac_folder = new StringBuilder () + .Append (prefix) + .Append (reference.Version) + .Append ("__"); + + for (int i = 0; i < reference.PublicKeyToken.Length; i++) + gac_folder.Append (reference.PublicKeyToken [i].ToString ("x2")); + + return Path.Combine ( + Path.Combine ( + Path.Combine (gac, reference.Name), gac_folder.ToString ()), + reference.Name + ".dll"); + } +#endif + } +} diff --git a/Mono.Cecil/CallSite.cs b/Mono.Cecil/CallSite.cs new file mode 100644 index 000000000..4430bd871 --- /dev/null +++ b/Mono.Cecil/CallSite.cs @@ -0,0 +1,54 @@ +// +// CallSite.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Text; + +namespace Mono.Cecil { + + public sealed class CallSite : MethodReference { + + public override string FullName { + get { + var signature = new StringBuilder (); + signature.Append (ReturnType.FullName); + this.MethodSignatureFullName (signature); + return signature.ToString (); + } + } + + public override ModuleDefinition Module { + get { return ReturnType.Module; } + } + + public override MethodDefinition Resolve () + { + return null; + } + } +} diff --git a/Mono.Cecil/CustomAttribute.cs b/Mono.Cecil/CustomAttribute.cs new file mode 100644 index 000000000..40b32ebdb --- /dev/null +++ b/Mono.Cecil/CustomAttribute.cs @@ -0,0 +1,232 @@ +// +// CustomAttribute.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +using Mono.Collections.Generic; + +namespace Mono.Cecil { + + public struct CustomAttributeArgument { + + readonly TypeReference type; + readonly object value; + + public TypeReference Type { + get { return type; } + } + + public object Value { + get { return value; } + } + + public CustomAttributeArgument (TypeReference type, object value) + { + Mixin.CheckType (type); + this.type = type; + this.value = value; + } + } + + public struct CustomAttributeNamedArgument { + + readonly string name; + readonly CustomAttributeArgument argument; + + public string Name { + get { return name; } + } + + public CustomAttributeArgument Argument { + get { return argument; } + } + + public CustomAttributeNamedArgument (string name, CustomAttributeArgument argument) + { + Mixin.CheckName (name); + this.name = name; + this.argument = argument; + } + } + + public interface ICustomAttribute { + + TypeReference AttributeType { get; } + + bool HasFields { get; } + bool HasProperties { get; } + Collection Fields { get; } + Collection Properties { get; } + } + + public sealed class CustomAttribute : ICustomAttribute { + + readonly internal uint signature; + internal bool resolved; + MethodReference constructor; + byte [] blob; + internal Collection arguments; + internal Collection fields; + internal Collection properties; + + public MethodReference Constructor { + get { return constructor; } + set { constructor = value; } + } + + public TypeReference AttributeType { + get { return constructor.DeclaringType; } + } + + public bool IsResolved { + get { return resolved; } + } + + public bool HasConstructorArguments { + get { + Resolve (); + + return !arguments.IsNullOrEmpty (); + } + } + + public Collection ConstructorArguments { + get { + Resolve (); + + return arguments ?? (arguments = new Collection ()); + } + } + + public bool HasFields { + get { + Resolve (); + + return !fields.IsNullOrEmpty (); + } + } + + public Collection Fields { + get { + Resolve (); + + return fields ?? (fields = new Collection ()); + } + } + + public bool HasProperties { + get { + Resolve (); + + return !properties.IsNullOrEmpty (); + } + } + + public Collection Properties { + get { + Resolve (); + + return properties ?? (properties = new Collection ()); + } + } + + internal bool HasImage { + get { return constructor != null && constructor.HasImage; } + } + + internal ModuleDefinition Module { + get { return constructor.Module; } + } + + internal CustomAttribute (uint signature, MethodReference constructor) + { + this.signature = signature; + this.constructor = constructor; + this.resolved = false; + } + + public CustomAttribute (MethodReference constructor) + { + this.constructor = constructor; + this.resolved = true; + } + + public CustomAttribute (MethodReference constructor, byte [] blob) + { + this.constructor = constructor; + this.resolved = false; + this.blob = blob; + } + + public byte [] GetBlob () + { + if (blob != null) + return blob; + + if (!HasImage || signature == 0) + throw new NotSupportedException (); + + return blob = Module.Read (this, (attribute, reader) => reader.ReadCustomAttributeBlob (attribute.signature)); + } + + void Resolve () + { + if (resolved || !HasImage) + return; + + try { + Module.Read (this, (attribute, reader) => { + reader.ReadCustomAttributeSignature (attribute); + return this; + }); + + resolved = true; + } catch (ResolutionException) { + if (arguments != null) + arguments.Clear (); + if (fields != null) + fields.Clear (); + if (properties != null) + properties.Clear (); + + resolved = false; + } + } + } + + static partial class Mixin { + + public static void CheckName (string name) + { + if (name == null) + throw new ArgumentNullException ("name"); + if (name.Length == 0) + throw new ArgumentException ("Empty name"); + } + } +} diff --git a/Mono.Cecil/DefaultAssemblyResolver.cs b/Mono.Cecil/DefaultAssemblyResolver.cs new file mode 100644 index 000000000..cac7974f9 --- /dev/null +++ b/Mono.Cecil/DefaultAssemblyResolver.cs @@ -0,0 +1,75 @@ +// +// DefaultAssemblyResolver.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Generic; + +namespace Mono.Cecil { + + public static class GlobalAssemblyResolver { + + public static readonly IAssemblyResolver Instance = new DefaultAssemblyResolver (); + } + + public class DefaultAssemblyResolver : BaseAssemblyResolver { + + readonly IDictionary cache; + + public DefaultAssemblyResolver () + { + cache = new Dictionary (); + } + + public override AssemblyDefinition Resolve (AssemblyNameReference name) + { + if (name == null) + throw new ArgumentNullException ("name"); + + AssemblyDefinition assembly; + if (cache.TryGetValue (name.FullName, out assembly)) + return assembly; + + assembly = base.Resolve (name); + cache [name.FullName] = assembly; + + return assembly; + } + + protected void RegisterAssembly (AssemblyDefinition assembly) + { + if (assembly == null) + throw new ArgumentNullException ("assembly"); + + var name = assembly.Name.FullName; + if (cache.ContainsKey (name)) + return; + + cache [name] = assembly; + } + } +} diff --git a/Mono.Cecil/EmbeddedResource.cs b/Mono.Cecil/EmbeddedResource.cs new file mode 100644 index 000000000..bb9f1f957 --- /dev/null +++ b/Mono.Cecil/EmbeddedResource.cs @@ -0,0 +1,105 @@ +// +// EmbeddedResource.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.IO; + +namespace Mono.Cecil { + + public sealed class EmbeddedResource : Resource { + + readonly MetadataReader reader; + + uint? offset; + byte [] data; + Stream stream; + + public override ResourceType ResourceType { + get { return ResourceType.Embedded; } + } + + public EmbeddedResource (string name, ManifestResourceAttributes attributes, byte [] data) : + base (name, attributes) + { + this.data = data; + } + + public EmbeddedResource (string name, ManifestResourceAttributes attributes, Stream stream) : + base (name, attributes) + { + this.stream = stream; + } + + internal EmbeddedResource (string name, ManifestResourceAttributes attributes, uint offset, MetadataReader reader) + : base (name, attributes) + { + this.offset = offset; + this.reader = reader; + } + + public Stream GetResourceStream () + { + if (stream != null) + return stream; + + if (data != null) + return new MemoryStream (data); + + if (offset.HasValue) + return reader.GetManagedResourceStream (offset.Value); + + throw new InvalidOperationException (); + } + + public byte [] GetResourceData () + { + if (stream != null) + return ReadStream (stream); + + if (data != null) + return data; + + if (offset.HasValue) + return reader.GetManagedResourceStream (offset.Value).ToArray (); + + throw new InvalidOperationException (); + } + + static byte [] ReadStream (Stream stream) + { + var length = (int) stream.Length; + var data = new byte [length]; + int offset = 0, read; + + while ((read = stream.Read (data, offset, length - offset)) > 0) + offset += read; + + return data; + } + } +} diff --git a/Mono.Cecil/EventAttributes.cs b/Mono.Cecil/EventAttributes.cs new file mode 100644 index 000000000..b5b097d4f --- /dev/null +++ b/Mono.Cecil/EventAttributes.cs @@ -0,0 +1,39 @@ +// +// EventAttributes.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace Mono.Cecil { + + [Flags] + public enum EventAttributes : ushort { + None = 0x0000, + SpecialName = 0x0200, // Event is special + RTSpecialName = 0x0400 // CLI provides 'special' behavior, depending upon the name of the event + } +} diff --git a/Mono.Cecil/EventDefinition.cs b/Mono.Cecil/EventDefinition.cs new file mode 100644 index 000000000..44ca8c092 --- /dev/null +++ b/Mono.Cecil/EventDefinition.cs @@ -0,0 +1,168 @@ +// +// EventDefinition.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using Mono.Collections.Generic; + +namespace Mono.Cecil { + + public sealed class EventDefinition : EventReference, IMemberDefinition { + + ushort attributes; + + Collection custom_attributes; + + internal MethodDefinition add_method; + internal MethodDefinition invoke_method; + internal MethodDefinition remove_method; + internal Collection other_methods; + + public EventAttributes Attributes { + get { return (EventAttributes) attributes; } + set { attributes = (ushort) value; } + } + + public MethodDefinition AddMethod { + get { + if (add_method != null) + return add_method; + + InitializeMethods (); + return add_method; + } + set { add_method = value; } + } + + public MethodDefinition InvokeMethod { + get { + if (invoke_method != null) + return invoke_method; + + InitializeMethods (); + return invoke_method; + } + set { invoke_method = value; } + } + + public MethodDefinition RemoveMethod { + get { + if (remove_method != null) + return remove_method; + + InitializeMethods (); + return remove_method; + } + set { remove_method = value; } + } + + public bool HasOtherMethods { + get { + if (other_methods != null) + return other_methods.Count > 0; + + InitializeMethods (); + return !other_methods.IsNullOrEmpty (); + } + } + + public Collection OtherMethods { + get { + if (other_methods != null) + return other_methods; + + InitializeMethods (); + + if (other_methods != null) + return other_methods; + + return other_methods = new Collection (); + } + } + + public bool HasCustomAttributes { + get { + if (custom_attributes != null) + return custom_attributes.Count > 0; + + return this.GetHasCustomAttributes (Module); + } + } + + public Collection CustomAttributes { + get { return custom_attributes ?? (custom_attributes = this.GetCustomAttributes (Module)); } + } + + #region EventAttributes + + public bool IsSpecialName { + get { return attributes.GetAttributes ((ushort) EventAttributes.SpecialName); } + set { attributes = attributes.SetAttributes ((ushort) EventAttributes.SpecialName, value); } + } + + public bool IsRuntimeSpecialName { + get { return attributes.GetAttributes ((ushort) FieldAttributes.RTSpecialName); } + set { attributes = attributes.SetAttributes ((ushort) FieldAttributes.RTSpecialName, value); } + } + + #endregion + + public new TypeDefinition DeclaringType { + get { return (TypeDefinition) base.DeclaringType; } + set { base.DeclaringType = value; } + } + + public override bool IsDefinition { + get { return true; } + } + + public EventDefinition (string name, EventAttributes attributes, TypeReference eventType) + : base (name, eventType) + { + this.attributes = (ushort) attributes; + this.token = new MetadataToken (TokenType.Event); + } + + void InitializeMethods () + { + if (add_method != null + || invoke_method != null + || remove_method != null) + return; + + var module = this.Module; + if (!module.HasImage ()) + return; + + module.Read (this, (@event, reader) => reader.ReadMethods (@event)); + } + + public override EventDefinition Resolve () + { + return this; + } + } +} diff --git a/Mono.Cecil/EventReference.cs b/Mono.Cecil/EventReference.cs new file mode 100644 index 000000000..bd1b0f7e4 --- /dev/null +++ b/Mono.Cecil/EventReference.cs @@ -0,0 +1,57 @@ +// +// EventReference.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace Mono.Cecil { + + public abstract class EventReference : MemberReference { + + TypeReference event_type; + + public TypeReference EventType { + get { return event_type; } + set { event_type = value; } + } + + public override string FullName { + get { return event_type.FullName + " " + MemberFullName (); } + } + + protected EventReference (string name, TypeReference eventType) + : base (name) + { + if (eventType == null) + throw new ArgumentNullException ("eventType"); + + event_type = eventType; + } + + public abstract EventDefinition Resolve (); + } +} diff --git a/Mono.Cecil/ExportedType.cs b/Mono.Cecil/ExportedType.cs new file mode 100644 index 000000000..fab7379bc --- /dev/null +++ b/Mono.Cecil/ExportedType.cs @@ -0,0 +1,249 @@ +// +// ExportedType.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace Mono.Cecil { + + public class ExportedType : IMetadataTokenProvider { + + string @namespace; + string name; + uint attributes; + IMetadataScope scope; + ModuleDefinition module; + int identifier; + ExportedType declaring_type; + internal MetadataToken token; + + public string Namespace { + get { return @namespace; } + set { @namespace = value; } + } + + public string Name { + get { return name; } + set { name = value; } + } + + public TypeAttributes Attributes { + get { return (TypeAttributes) attributes; } + set { attributes = (uint) value; } + } + + public IMetadataScope Scope { + get { + if (declaring_type != null) + return declaring_type.Scope; + + return scope; + } + } + + public ExportedType DeclaringType { + get { return declaring_type; } + set { declaring_type = value; } + } + + public MetadataToken MetadataToken { + get { return token; } + set { token = value; } + } + + public int Identifier { + get { return identifier; } + set { identifier = value; } + } + + #region TypeAttributes + + public bool IsNotPublic { + get { return attributes.GetMaskedAttributes ((uint) TypeAttributes.VisibilityMask, (uint) TypeAttributes.NotPublic); } + set { attributes = attributes.SetMaskedAttributes ((uint) TypeAttributes.VisibilityMask, (uint) TypeAttributes.NotPublic, value); } + } + + public bool IsPublic { + get { return attributes.GetMaskedAttributes ((uint) TypeAttributes.VisibilityMask, (uint) TypeAttributes.Public); } + set { attributes = attributes.SetMaskedAttributes ((uint) TypeAttributes.VisibilityMask, (uint) TypeAttributes.Public, value); } + } + + public bool IsNestedPublic { + get { return attributes.GetMaskedAttributes ((uint) TypeAttributes.VisibilityMask, (uint) TypeAttributes.NestedPublic); } + set { attributes = attributes.SetMaskedAttributes ((uint) TypeAttributes.VisibilityMask, (uint) TypeAttributes.NestedPublic, value); } + } + + public bool IsNestedPrivate { + get { return attributes.GetMaskedAttributes ((uint) TypeAttributes.VisibilityMask, (uint) TypeAttributes.NestedPrivate); } + set { attributes = attributes.SetMaskedAttributes ((uint) TypeAttributes.VisibilityMask, (uint) TypeAttributes.NestedPrivate, value); } + } + + public bool IsNestedFamily { + get { return attributes.GetMaskedAttributes ((uint) TypeAttributes.VisibilityMask, (uint) TypeAttributes.NestedFamily); } + set { attributes = attributes.SetMaskedAttributes ((uint) TypeAttributes.VisibilityMask, (uint) TypeAttributes.NestedFamily, value); } + } + + public bool IsNestedAssembly { + get { return attributes.GetMaskedAttributes ((uint) TypeAttributes.VisibilityMask, (uint) TypeAttributes.NestedAssembly); } + set { attributes = attributes.SetMaskedAttributes ((uint) TypeAttributes.VisibilityMask, (uint) TypeAttributes.NestedAssembly, value); } + } + + public bool IsNestedFamilyAndAssembly { + get { return attributes.GetMaskedAttributes ((uint) TypeAttributes.VisibilityMask, (uint) TypeAttributes.NestedFamANDAssem); } + set { attributes = attributes.SetMaskedAttributes ((uint) TypeAttributes.VisibilityMask, (uint) TypeAttributes.NestedFamANDAssem, value); } + } + + public bool IsNestedFamilyOrAssembly { + get { return attributes.GetMaskedAttributes ((uint) TypeAttributes.VisibilityMask, (uint) TypeAttributes.NestedFamORAssem); } + set { attributes = attributes.SetMaskedAttributes ((uint) TypeAttributes.VisibilityMask, (uint) TypeAttributes.NestedFamORAssem, value); } + } + + public bool IsAutoLayout { + get { return attributes.GetMaskedAttributes ((uint) TypeAttributes.LayoutMask, (uint) TypeAttributes.AutoLayout); } + set { attributes = attributes.SetMaskedAttributes ((uint) TypeAttributes.LayoutMask, (uint) TypeAttributes.AutoLayout, value); } + } + + public bool IsSequentialLayout { + get { return attributes.GetMaskedAttributes ((uint) TypeAttributes.LayoutMask, (uint) TypeAttributes.SequentialLayout); } + set { attributes = attributes.SetMaskedAttributes ((uint) TypeAttributes.LayoutMask, (uint) TypeAttributes.SequentialLayout, value); } + } + + public bool IsExplicitLayout { + get { return attributes.GetMaskedAttributes ((uint) TypeAttributes.LayoutMask, (uint) TypeAttributes.ExplicitLayout); } + set { attributes = attributes.SetMaskedAttributes ((uint) TypeAttributes.LayoutMask, (uint) TypeAttributes.ExplicitLayout, value); } + } + + public bool IsClass { + get { return attributes.GetMaskedAttributes ((uint) TypeAttributes.ClassSemanticMask, (uint) TypeAttributes.Class); } + set { attributes = attributes.SetMaskedAttributes ((uint) TypeAttributes.ClassSemanticMask, (uint) TypeAttributes.Class, value); } + } + + public bool IsInterface { + get { return attributes.GetMaskedAttributes ((uint) TypeAttributes.ClassSemanticMask, (uint) TypeAttributes.Interface); } + set { attributes = attributes.SetMaskedAttributes ((uint) TypeAttributes.ClassSemanticMask, (uint) TypeAttributes.Interface, value); } + } + + public bool IsAbstract { + get { return attributes.GetAttributes ((uint) TypeAttributes.Abstract); } + set { attributes = attributes.SetAttributes ((uint) TypeAttributes.Abstract, value); } + } + + public bool IsSealed { + get { return attributes.GetAttributes ((uint) TypeAttributes.Sealed); } + set { attributes = attributes.SetAttributes ((uint) TypeAttributes.Sealed, value); } + } + + public bool IsSpecialName { + get { return attributes.GetAttributes ((uint) TypeAttributes.SpecialName); } + set { attributes = attributes.SetAttributes ((uint) TypeAttributes.SpecialName, value); } + } + + public bool IsImport { + get { return attributes.GetAttributes ((uint) TypeAttributes.Import); } + set { attributes = attributes.SetAttributes ((uint) TypeAttributes.Import, value); } + } + + public bool IsSerializable { + get { return attributes.GetAttributes ((uint) TypeAttributes.Serializable); } + set { attributes = attributes.SetAttributes ((uint) TypeAttributes.Serializable, value); } + } + + public bool IsAnsiClass { + get { return attributes.GetMaskedAttributes ((uint) TypeAttributes.StringFormatMask, (uint) TypeAttributes.AnsiClass); } + set { attributes = attributes.SetMaskedAttributes ((uint) TypeAttributes.StringFormatMask, (uint) TypeAttributes.AnsiClass, value); } + } + + public bool IsUnicodeClass { + get { return attributes.GetMaskedAttributes ((uint) TypeAttributes.StringFormatMask, (uint) TypeAttributes.UnicodeClass); } + set { attributes = attributes.SetMaskedAttributes ((uint) TypeAttributes.StringFormatMask, (uint) TypeAttributes.UnicodeClass, value); } + } + + public bool IsAutoClass { + get { return attributes.GetMaskedAttributes ((uint) TypeAttributes.StringFormatMask, (uint) TypeAttributes.AutoClass); } + set { attributes = attributes.SetMaskedAttributes ((uint) TypeAttributes.StringFormatMask, (uint) TypeAttributes.AutoClass, value); } + } + + public bool IsBeforeFieldInit { + get { return attributes.GetAttributes ((uint) TypeAttributes.BeforeFieldInit); } + set { attributes = attributes.SetAttributes ((uint) TypeAttributes.BeforeFieldInit, value); } + } + + public bool IsRuntimeSpecialName { + get { return attributes.GetAttributes ((uint) TypeAttributes.RTSpecialName); } + set { attributes = attributes.SetAttributes ((uint) TypeAttributes.RTSpecialName, value); } + } + + public bool HasSecurity { + get { return attributes.GetAttributes ((uint) TypeAttributes.HasSecurity); } + set { attributes = attributes.SetAttributes ((uint) TypeAttributes.HasSecurity, value); } + } + + #endregion + + public bool IsForwarder { + get { return attributes.GetAttributes ((uint) TypeAttributes.Forwarder); } + set { attributes = attributes.SetAttributes ((uint) TypeAttributes.Forwarder, value); } + } + + public string FullName { + get { + if (declaring_type != null) + return declaring_type.FullName + "/" + name; + + if (string.IsNullOrEmpty (@namespace)) + return name; + + return @namespace + "." + name; + } + } + + public ExportedType (string @namespace, string name, ModuleDefinition module, IMetadataScope scope) + { + this.@namespace = @namespace; + this.name = name; + this.scope = scope; + this.module = module; + } + + public override string ToString () + { + return FullName; + } + + public TypeDefinition Resolve () + { + return module.Resolve (CreateReference ()); + } + + internal TypeReference CreateReference () + { + return new TypeReference (@namespace, name, module, scope) { + DeclaringType = declaring_type != null ? declaring_type.CreateReference () : null, + }; + } + } +} diff --git a/Mono.Cecil/FieldAttributes.cs b/Mono.Cecil/FieldAttributes.cs new file mode 100644 index 000000000..947a8770a --- /dev/null +++ b/Mono.Cecil/FieldAttributes.cs @@ -0,0 +1,59 @@ +// +// FieldAttributes.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace Mono.Cecil { + + [Flags] + public enum FieldAttributes : ushort { + FieldAccessMask = 0x0007, + CompilerControlled = 0x0000, // Member not referenceable + Private = 0x0001, // Accessible only by the parent type + FamANDAssem = 0x0002, // Accessible by sub-types only in this assembly + Assembly = 0x0003, // Accessible by anyone in the Assembly + Family = 0x0004, // Accessible only by type and sub-types + FamORAssem = 0x0005, // Accessible by sub-types anywhere, plus anyone in the assembly + Public = 0x0006, // Accessible by anyone who has visibility to this scope field contract attributes + + Static = 0x0010, // Defined on type, else per instance + InitOnly = 0x0020, // Field may only be initialized, not written after init + Literal = 0x0040, // Value is compile time constant + NotSerialized = 0x0080, // Field does not have to be serialized when type is remoted + SpecialName = 0x0200, // Field is special + + // Interop Attributes + PInvokeImpl = 0x2000, // Implementation is forwarded through PInvoke + + // Additional flags + RTSpecialName = 0x0400, // CLI provides 'special' behavior, depending upon the name of the field + HasFieldMarshal = 0x1000, // Field has marshalling information + HasDefault = 0x8000, // Field has default + HasFieldRVA = 0x0100 // Field has RVA + } +} diff --git a/Mono.Cecil/FieldDefinition.cs b/Mono.Cecil/FieldDefinition.cs new file mode 100644 index 000000000..c60a94005 --- /dev/null +++ b/Mono.Cecil/FieldDefinition.cs @@ -0,0 +1,279 @@ +// +// FieldDefinition.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using Mono.Collections.Generic; + +namespace Mono.Cecil { + + public sealed class FieldDefinition : FieldReference, IMemberDefinition, IConstantProvider, IMarshalInfoProvider { + + ushort attributes; + Collection custom_attributes; + + int offset = Mixin.NotResolvedMarker; + + internal int rva = Mixin.NotResolvedMarker; + byte [] initial_value; + + object constant = Mixin.NotResolved; + + MarshalInfo marshal_info; + + void ResolveLayout () + { + if (offset != Mixin.NotResolvedMarker) + return; + + if (!HasImage) { + offset = Mixin.NoDataMarker; + return; + } + + offset = Module.Read (this, (field, reader) => reader.ReadFieldLayout (field)); + } + + public bool HasLayoutInfo { + get { + if (offset >= 0) + return true; + + ResolveLayout (); + + return offset >= 0; + } + } + + public int Offset { + get { + if (offset >= 0) + return offset; + + ResolveLayout (); + + return offset >= 0 ? offset : -1; + } + set { offset = value; } + } + + void ResolveRVA () + { + if (rva != Mixin.NotResolvedMarker) + return; + + if (!HasImage) + return; + + rva = Module.Read (this, (field, reader) => reader.ReadFieldRVA (field)); + } + + public int RVA { + get { + if (rva > 0) + return rva; + + ResolveRVA (); + + return rva > 0 ? rva : 0; + } + } + + public byte [] InitialValue { + get { + if (initial_value != null) + return initial_value; + + ResolveRVA (); + + if (initial_value == null) + initial_value = Empty.Array; + + return initial_value; + } + set { initial_value = value; } + } + + public FieldAttributes Attributes { + get { return (FieldAttributes) attributes; } + set { attributes = (ushort) value; } + } + + public bool HasConstant { + get { + ResolveConstant (); + + return constant != Mixin.NoValue; + } + set { if (!value) constant = Mixin.NoValue; } + } + + public object Constant { + get { return HasConstant ? constant : null; } + set { constant = value; } + } + + void ResolveConstant () + { + if (constant != Mixin.NotResolved) + return; + + this.ResolveConstant (ref constant, Module); + } + + public bool HasCustomAttributes { + get { + if (custom_attributes != null) + return custom_attributes.Count > 0; + + return this.GetHasCustomAttributes (Module); + } + } + + public Collection CustomAttributes { + get { return custom_attributes ?? (custom_attributes = this.GetCustomAttributes (Module)); } + } + + public bool HasMarshalInfo { + get { + if (marshal_info != null) + return true; + + return this.GetHasMarshalInfo (Module); + } + } + + public MarshalInfo MarshalInfo { + get { return marshal_info ?? (marshal_info = this.GetMarshalInfo (Module)); } + set { marshal_info = value; } + } + + #region FieldAttributes + + public bool IsCompilerControlled { + get { return attributes.GetMaskedAttributes ((ushort) FieldAttributes.FieldAccessMask, (ushort) FieldAttributes.CompilerControlled); } + set { attributes = attributes.SetMaskedAttributes ((ushort) FieldAttributes.FieldAccessMask, (ushort) FieldAttributes.CompilerControlled, value); } + } + + public bool IsPrivate { + get { return attributes.GetMaskedAttributes ((ushort) FieldAttributes.FieldAccessMask, (ushort) FieldAttributes.Private); } + set { attributes = attributes.SetMaskedAttributes ((ushort) FieldAttributes.FieldAccessMask, (ushort) FieldAttributes.Private, value); } + } + + public bool IsFamilyAndAssembly { + get { return attributes.GetMaskedAttributes ((ushort) FieldAttributes.FieldAccessMask, (ushort) FieldAttributes.FamANDAssem); } + set { attributes = attributes.SetMaskedAttributes ((ushort) FieldAttributes.FieldAccessMask, (ushort) FieldAttributes.FamANDAssem, value); } + } + + public bool IsAssembly { + get { return attributes.GetMaskedAttributes ((ushort) FieldAttributes.FieldAccessMask, (ushort) FieldAttributes.Assembly); } + set { attributes = attributes.SetMaskedAttributes ((ushort) FieldAttributes.FieldAccessMask, (ushort) FieldAttributes.Assembly, value); } + } + + public bool IsFamily { + get { return attributes.GetMaskedAttributes ((ushort) FieldAttributes.FieldAccessMask, (ushort) FieldAttributes.Family); } + set { attributes = attributes.SetMaskedAttributes ((ushort) FieldAttributes.FieldAccessMask, (ushort) FieldAttributes.Family, value); } + } + + public bool IsFamilyOrAssembly { + get { return attributes.GetMaskedAttributes ((ushort) FieldAttributes.FieldAccessMask, (ushort) FieldAttributes.FamORAssem); } + set { attributes = attributes.SetMaskedAttributes ((ushort) FieldAttributes.FieldAccessMask, (ushort) FieldAttributes.FamORAssem, value); } + } + + public bool IsPublic { + get { return attributes.GetMaskedAttributes ((ushort) FieldAttributes.FieldAccessMask, (ushort) FieldAttributes.Public); } + set { attributes = attributes.SetMaskedAttributes ((ushort) FieldAttributes.FieldAccessMask, (ushort) FieldAttributes.Public, value); } + } + + public bool IsStatic { + get { return attributes.GetAttributes ((ushort) FieldAttributes.Static); } + set { attributes = attributes.SetAttributes ((ushort) FieldAttributes.Static, value); } + } + + public bool IsInitOnly { + get { return attributes.GetAttributes ((ushort) FieldAttributes.InitOnly); } + set { attributes = attributes.SetAttributes ((ushort) FieldAttributes.InitOnly, value); } + } + + public bool IsLiteral { + get { return attributes.GetAttributes ((ushort) FieldAttributes.Literal); } + set { attributes = attributes.SetAttributes ((ushort) FieldAttributes.Literal, value); } + } + + public bool IsNotSerialized { + get { return attributes.GetAttributes ((ushort) FieldAttributes.NotSerialized); } + set { attributes = attributes.SetAttributes ((ushort) FieldAttributes.NotSerialized, value); } + } + + public bool IsSpecialName { + get { return attributes.GetAttributes ((ushort) FieldAttributes.SpecialName); } + set { attributes = attributes.SetAttributes ((ushort) FieldAttributes.SpecialName, value); } + } + + public bool IsPInvokeImpl { + get { return attributes.GetAttributes ((ushort) FieldAttributes.PInvokeImpl); } + set { attributes = attributes.SetAttributes ((ushort) FieldAttributes.PInvokeImpl, value); } + } + + public bool IsRuntimeSpecialName { + get { return attributes.GetAttributes ((ushort) FieldAttributes.RTSpecialName); } + set { attributes = attributes.SetAttributes ((ushort) FieldAttributes.RTSpecialName, value); } + } + + public bool HasDefault { + get { return attributes.GetAttributes ((ushort) FieldAttributes.HasDefault); } + set { attributes = attributes.SetAttributes ((ushort) FieldAttributes.HasDefault, value); } + } + + #endregion + + public override bool IsDefinition { + get { return true; } + } + + public new TypeDefinition DeclaringType { + get { return (TypeDefinition) base.DeclaringType; } + set { base.DeclaringType = value; } + } + + public FieldDefinition (string name, FieldAttributes attributes, TypeReference fieldType) + : base (name, fieldType) + { + this.attributes = (ushort) attributes; + } + + public override FieldDefinition Resolve () + { + return this; + } + } + + static partial class Mixin { + + public const int NotResolvedMarker = -2; + public const int NoDataMarker = -1; + } +} diff --git a/Mono.Cecil/FieldReference.cs b/Mono.Cecil/FieldReference.cs new file mode 100644 index 000000000..1c812bb90 --- /dev/null +++ b/Mono.Cecil/FieldReference.cs @@ -0,0 +1,83 @@ +// +// FieldReference.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace Mono.Cecil { + + public class FieldReference : MemberReference { + + TypeReference field_type; + + public TypeReference FieldType { + get { return field_type; } + set { field_type = value; } + } + + public override string FullName { + get { return field_type.FullName + " " + MemberFullName (); } + } + + internal override bool ContainsGenericParameter { + get { return field_type.ContainsGenericParameter || base.ContainsGenericParameter; } + } + + internal FieldReference () + { + this.token = new MetadataToken (TokenType.MemberRef); + } + + public FieldReference (string name, TypeReference fieldType) + : base (name) + { + if (fieldType == null) + throw new ArgumentNullException ("fieldType"); + + this.field_type = fieldType; + this.token = new MetadataToken (TokenType.MemberRef); + } + + public FieldReference (string name, TypeReference fieldType, TypeReference declaringType) + : this (name, fieldType) + { + if (declaringType == null) + throw new ArgumentNullException("declaringType"); + + this.DeclaringType = declaringType; + } + + public virtual FieldDefinition Resolve () + { + var module = this.Module; + if (module == null) + throw new NotSupportedException (); + + return module.Resolve (this); + } + } +} diff --git a/Mono.Cecil/FileAttributes.cs b/Mono.Cecil/FileAttributes.cs new file mode 100644 index 000000000..6c2781c62 --- /dev/null +++ b/Mono.Cecil/FileAttributes.cs @@ -0,0 +1,35 @@ +// +// FileAttributes.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace Mono.Cecil { + + enum FileAttributes : uint { + ContainsMetaData = 0x0000, // This is not a resource file + ContainsNoMetaData = 0x0001, // This is a resource file or other non-metadata-containing file + } +} diff --git a/Mono.Cecil/FunctionPointerType.cs b/Mono.Cecil/FunctionPointerType.cs new file mode 100644 index 000000000..f7bf08c3f --- /dev/null +++ b/Mono.Cecil/FunctionPointerType.cs @@ -0,0 +1,128 @@ +// +// FunctionPointerType.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Text; +using Mono.Collections.Generic; +using MD = Mono.Cecil.Metadata; + +namespace Mono.Cecil { + + public sealed class FunctionPointerType : TypeSpecification, IMethodSignature { + + readonly MethodReference function; + + public bool HasThis { + get { return function.HasThis; } + set { function.HasThis = value; } + } + + public bool ExplicitThis { + get { return function.ExplicitThis; } + set { function.ExplicitThis = value; } + } + + public MethodCallingConvention CallingConvention { + get { return function.CallingConvention; } + set { function.CallingConvention = value; } + } + + public bool HasParameters { + get { return function.HasParameters; } + } + + public Collection Parameters { + get { return function.Parameters; } + } + + public TypeReference ReturnType { + get { return function.MethodReturnType.ReturnType; } + set { function.MethodReturnType.ReturnType = value; } + } + + public MethodReturnType MethodReturnType { + get { return function.MethodReturnType; } + } + + public override string Name { + get { return function.Name; } + set { throw new InvalidOperationException (); } + } + + public override string Namespace { + get { return string.Empty; } + set { throw new InvalidOperationException (); } + } + + public override ModuleDefinition Module { + get { return ReturnType.Module; } + } + + public override IMetadataScope Scope { + get { return function.ReturnType.Scope; } + } + + public override bool IsFunctionPointer { + get { return true; } + } + + internal override bool ContainsGenericParameter { + get { return function.ContainsGenericParameter; } + } + + public override string FullName { + get { + var signature = new StringBuilder (); + signature.Append (function.Name); + signature.Append (" "); + signature.Append (function.ReturnType.FullName); + signature.Append (" *"); + this.MethodSignatureFullName (signature); + return signature.ToString (); + } + } + + public FunctionPointerType () + : base (null) + { + this.function = new MethodReference (); + this.function.Name = "method"; + this.etype = MD.ElementType.FnPtr; + } + + public override TypeDefinition Resolve () + { + return null; + } + + public override TypeReference GetElementType () + { + return this; + } + } +} diff --git a/Mono.Cecil/GenericInstanceMethod.cs b/Mono.Cecil/GenericInstanceMethod.cs new file mode 100644 index 000000000..d5d8d4ecd --- /dev/null +++ b/Mono.Cecil/GenericInstanceMethod.cs @@ -0,0 +1,90 @@ +// +// GenericInstanceMethod.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Text; + +using Mono.Collections.Generic; + +namespace Mono.Cecil { + + public sealed class GenericInstanceMethod : MethodSpecification, IGenericInstance, IGenericContext { + + Collection arguments; + + public bool HasGenericArguments { + get { return !arguments.IsNullOrEmpty (); } + } + + public Collection GenericArguments { + get { + if (arguments == null) + arguments = new Collection (); + + return arguments; + } + } + + public override bool IsGenericInstance { + get { return true; } + } + + IGenericParameterProvider IGenericContext.Method { + get { return ElementMethod; } + } + + IGenericParameterProvider IGenericContext.Type { + get { return ElementMethod.DeclaringType; } + } + + internal override bool ContainsGenericParameter { + get { return this.ContainsGenericParameter () || base.ContainsGenericParameter; } + } + + public override string FullName { + get { + var signature = new StringBuilder (); + var method = this.ElementMethod; + signature.Append (method.ReturnType.FullName) + .Append (" ") + .Append (method.DeclaringType.FullName) + .Append ("::") + .Append (method.Name); + this.GenericInstanceFullName (signature); + this.MethodSignatureFullName (signature); + return signature.ToString (); + + } + } + + public GenericInstanceMethod (MethodReference method) + : base (method) + { + } + } +} diff --git a/Mono.Cecil/GenericInstanceType.cs b/Mono.Cecil/GenericInstanceType.cs new file mode 100644 index 000000000..46c048bcd --- /dev/null +++ b/Mono.Cecil/GenericInstanceType.cs @@ -0,0 +1,88 @@ +// +// GenericInstanceType.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Text; + +using Mono.Collections.Generic; + +using MD = Mono.Cecil.Metadata; + +namespace Mono.Cecil { + + public sealed class GenericInstanceType : TypeSpecification, IGenericInstance, IGenericContext { + + Collection arguments; + + public bool HasGenericArguments { + get { return !arguments.IsNullOrEmpty (); } + } + + public Collection GenericArguments { + get { + if (arguments == null) + arguments = new Collection (); + + return arguments; + } + } + + public override TypeReference DeclaringType { + get { return ElementType.DeclaringType; } + set { throw new NotSupportedException (); } + } + + public override string FullName { + get { + var name = new StringBuilder (); + name.Append (base.FullName); + this.GenericInstanceFullName (name); + return name.ToString (); + } + } + + public override bool IsGenericInstance { + get { return true; } + } + + internal override bool ContainsGenericParameter { + get { return this.ContainsGenericParameter () || base.ContainsGenericParameter; } + } + + IGenericParameterProvider IGenericContext.Type { + get { return ElementType; } + } + + public GenericInstanceType (TypeReference type) + : base (type) + { + base.IsValueType = type.IsValueType; + this.etype = MD.ElementType.GenericInst; + } + } +} diff --git a/Mono.Cecil/GenericParameter.cs b/Mono.Cecil/GenericParameter.cs new file mode 100644 index 000000000..d3e5a15d5 --- /dev/null +++ b/Mono.Cecil/GenericParameter.cs @@ -0,0 +1,201 @@ +// +// GenericParameter.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +using Mono.Collections.Generic; + +using Mono.Cecil.Metadata; + +namespace Mono.Cecil { + + public sealed class GenericParameter : TypeReference, ICustomAttributeProvider { + + readonly IGenericParameterProvider owner; + + ushort attributes; + Collection constraints; + Collection custom_attributes; + + public GenericParameterAttributes Attributes { + get { return (GenericParameterAttributes) attributes; } + set { attributes = (ushort) value; } + } + + public int Position { + get { + if (owner == null) + return -1; + + return owner.GenericParameters.IndexOf (this); + } + } + + public IGenericParameterProvider Owner { + get { return owner; } + } + + public bool HasConstraints { + get { + if (constraints != null) + return constraints.Count > 0; + + if (HasImage) + return Module.Read (this, (generic_parameter, reader) => reader.HasGenericConstraints (generic_parameter)); + + return false; + } + } + + public Collection Constraints { + get { + if (constraints != null) + return constraints; + + if (HasImage) + return constraints = Module.Read (this, (generic_parameter, reader) => reader.ReadGenericConstraints (generic_parameter)); + + return constraints = new Collection (); + } + } + + public bool HasCustomAttributes { + get { + if (custom_attributes != null) + return custom_attributes.Count > 0; + + return this.GetHasCustomAttributes (Module); + } + } + + public Collection CustomAttributes { + get { return custom_attributes ?? (custom_attributes = this.GetCustomAttributes (Module)); } + } + + internal new bool HasImage { + get { return Module != null && Module.HasImage; } + } + + public override IMetadataScope Scope { + get { + if (owner.GenericParameterType == GenericParameterType.Method) + return ((MethodReference) owner).DeclaringType.Scope; + + return ((TypeReference) owner).Scope; + } + } + + public override ModuleDefinition Module { + get { return ((MemberReference) owner).Module; } + } + + public override string Name { + get { + if (!string.IsNullOrEmpty (base.Name)) + return base.Name; + + return base.Name = (owner.GenericParameterType == GenericParameterType.Type ? "!" : "!!") + Position; + } + } + + public override string Namespace { + get { return string.Empty; } + set { throw new InvalidOperationException (); } + } + + public override string FullName { + get { return Name; } + } + + public override bool IsGenericParameter { + get { return true; } + } + + internal override bool ContainsGenericParameter { + get { return true; } + } + + public override MetadataType MetadataType { + get { return (MetadataType) etype; } + } + + #region GenericParameterAttributes + + public bool IsNonVariant { + get { return attributes.GetMaskedAttributes ((ushort) GenericParameterAttributes.VarianceMask, (ushort) GenericParameterAttributes.NonVariant); } + set { attributes = attributes.SetMaskedAttributes ((ushort) GenericParameterAttributes.VarianceMask, (ushort) GenericParameterAttributes.NonVariant, value); } + } + + public bool IsCovariant { + get { return attributes.GetMaskedAttributes ((ushort) GenericParameterAttributes.VarianceMask, (ushort) GenericParameterAttributes.Covariant); } + set { attributes = attributes.SetMaskedAttributes ((ushort) GenericParameterAttributes.VarianceMask, (ushort) GenericParameterAttributes.Covariant, value); } + } + + public bool IsContravariant { + get { return attributes.GetMaskedAttributes ((ushort) GenericParameterAttributes.VarianceMask, (ushort) GenericParameterAttributes.Contravariant); } + set { attributes = attributes.SetMaskedAttributes ((ushort) GenericParameterAttributes.VarianceMask, (ushort) GenericParameterAttributes.Contravariant, value); } + } + + public bool HasReferenceTypeConstraint { + get { return attributes.GetAttributes ((ushort) GenericParameterAttributes.ReferenceTypeConstraint); } + set { attributes = attributes.SetAttributes ((ushort) GenericParameterAttributes.ReferenceTypeConstraint, value); } + } + + public bool HasNotNullableValueTypeConstraint { + get { return attributes.GetAttributes ((ushort) GenericParameterAttributes.NotNullableValueTypeConstraint); } + set { attributes = attributes.SetAttributes ((ushort) GenericParameterAttributes.NotNullableValueTypeConstraint, value); } + } + + public bool HasDefaultConstructorConstraint { + get { return attributes.GetAttributes ((ushort) GenericParameterAttributes.DefaultConstructorConstraint); } + set { attributes = attributes.SetAttributes ((ushort) GenericParameterAttributes.DefaultConstructorConstraint, value); } + } + + #endregion + + public GenericParameter (IGenericParameterProvider owner) + : this (string.Empty, owner) + { + } + + public GenericParameter (string name, IGenericParameterProvider owner) + : base (string.Empty, name) + { + if (owner == null) + throw new ArgumentNullException (); + + this.owner = owner; + this.etype = owner.GenericParameterType == GenericParameterType.Type ? ElementType.Var : ElementType.MVar; + } + + public override TypeDefinition Resolve () + { + return null; + } + } +} diff --git a/Mono.Cecil/GenericParameterAttributes.cs b/Mono.Cecil/GenericParameterAttributes.cs new file mode 100644 index 000000000..89996140e --- /dev/null +++ b/Mono.Cecil/GenericParameterAttributes.cs @@ -0,0 +1,45 @@ +// +// GenericParameterAttributes.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace Mono.Cecil { + + [Flags] + public enum GenericParameterAttributes : ushort { + VarianceMask = 0x0003, + NonVariant = 0x0000, + Covariant = 0x0001, + Contravariant = 0x0002, + + SpecialConstraintMask = 0x001c, + ReferenceTypeConstraint = 0x0004, + NotNullableValueTypeConstraint = 0x0008, + DefaultConstructorConstraint = 0x0010 + } +} diff --git a/Mono.Cecil/IConstantProvider.cs b/Mono.Cecil/IConstantProvider.cs new file mode 100644 index 000000000..e3338cf20 --- /dev/null +++ b/Mono.Cecil/IConstantProvider.cs @@ -0,0 +1,52 @@ +// +// IConstantProvider.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace Mono.Cecil { + + public interface IConstantProvider : IMetadataTokenProvider { + + bool HasConstant { get; set; } + object Constant { get; set; } + } + + static partial class Mixin { + + internal static object NoValue = new object (); + internal static object NotResolved = new object (); + + public static void ResolveConstant ( + this IConstantProvider self, + ref object constant, + ModuleDefinition module) + { + constant = module.HasImage () + ? module.Read (self, (provider, reader) => reader.ReadConstant (provider)) + : Mixin.NoValue; + } + } +} diff --git a/Mono.Cecil/ICustomAttributeProvider.cs b/Mono.Cecil/ICustomAttributeProvider.cs new file mode 100644 index 000000000..08e5f925a --- /dev/null +++ b/Mono.Cecil/ICustomAttributeProvider.cs @@ -0,0 +1,62 @@ +// +// ICustomAttributeProvider.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +using Mono.Collections.Generic; + +namespace Mono.Cecil { + + public interface ICustomAttributeProvider : IMetadataTokenProvider { + + Collection CustomAttributes { get; } + + bool HasCustomAttributes { get; } + } + + static partial class Mixin { + + public static bool GetHasCustomAttributes ( + this ICustomAttributeProvider self, + ModuleDefinition module) + { + return module.HasImage () + ? module.Read (self, (provider, reader) => reader.HasCustomAttributes (provider)) + : false; + } + + public static Collection GetCustomAttributes ( + this ICustomAttributeProvider self, + ModuleDefinition module) + { + return module.HasImage () + ? module.Read (self, (provider, reader) => reader.ReadCustomAttributes (provider)) + : new Collection (); + } + } +} diff --git a/Mono.Cecil/IGenericInstance.cs b/Mono.Cecil/IGenericInstance.cs new file mode 100644 index 000000000..2750ad0a6 --- /dev/null +++ b/Mono.Cecil/IGenericInstance.cs @@ -0,0 +1,66 @@ +// +// IGenericInstance.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System.Text; + +using Mono.Collections.Generic; + +namespace Mono.Cecil { + + public interface IGenericInstance : IMetadataTokenProvider { + + bool HasGenericArguments { get; } + Collection GenericArguments { get; } + } + + static partial class Mixin { + + public static bool ContainsGenericParameter (this IGenericInstance self) + { + var arguments = self.GenericArguments; + + for (int i = 0; i < arguments.Count; i++) + if (arguments [i].ContainsGenericParameter) + return true; + + return false; + } + + public static void GenericInstanceFullName (this IGenericInstance self, StringBuilder builder) + { + builder.Append ("<"); + var arguments = self.GenericArguments; + for (int i = 0; i < arguments.Count; i++) { + if (i > 0) + builder.Append (","); + builder.Append (arguments [i].FullName); + } + builder.Append (">"); + } + } +} diff --git a/Mono.Cecil/IGenericParameterProvider.cs b/Mono.Cecil/IGenericParameterProvider.cs new file mode 100644 index 000000000..27d1669fc --- /dev/null +++ b/Mono.Cecil/IGenericParameterProvider.cs @@ -0,0 +1,75 @@ +// +// IGenericParameterProvider.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + + +using Mono.Collections.Generic; + +namespace Mono.Cecil { + + public interface IGenericParameterProvider : IMetadataTokenProvider { + + bool HasGenericParameters { get; } + bool IsDefinition { get; } + ModuleDefinition Module { get; } + Collection GenericParameters { get; } + GenericParameterType GenericParameterType { get; } + } + + public enum GenericParameterType { + Type, + Method + } + + interface IGenericContext { + + bool IsDefinition { get; } + IGenericParameterProvider Type { get; } + IGenericParameterProvider Method { get; } + } + + static partial class Mixin { + + public static bool GetHasGenericParameters ( + this IGenericParameterProvider self, + ModuleDefinition module) + { + return module.HasImage () + ? module.Read (self, (provider, reader) => reader.HasGenericParameters (provider)) + : false; + } + + public static Collection GetGenericParameters ( + this IGenericParameterProvider self, + ModuleDefinition module) + { + return module.HasImage () + ? module.Read (self, (provider, reader) => reader.ReadGenericParameters (provider)) + : new Collection (); + } + } +} diff --git a/Mono.Cecil/IMarshalInfoProvider.cs b/Mono.Cecil/IMarshalInfoProvider.cs new file mode 100644 index 000000000..a3bba6d0d --- /dev/null +++ b/Mono.Cecil/IMarshalInfoProvider.cs @@ -0,0 +1,57 @@ +// +// IMarshalInfoProvider.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace Mono.Cecil { + + public interface IMarshalInfoProvider : IMetadataTokenProvider { + + bool HasMarshalInfo { get; } + MarshalInfo MarshalInfo { get; set; } + } + + static partial class Mixin { + + public static bool GetHasMarshalInfo ( + this IMarshalInfoProvider self, + ModuleDefinition module) + { + return module.HasImage () + ? module.Read (self, (provider, reader) => reader.HasMarshalInfo (provider)) + : false; + } + + public static MarshalInfo GetMarshalInfo ( + this IMarshalInfoProvider self, + ModuleDefinition module) + { + return module.HasImage () + ? module.Read (self, (provider, reader) => reader.ReadMarshalInfo (provider)) + : null; + } + } +} diff --git a/Mono.Cecil/IMemberDefinition.cs b/Mono.Cecil/IMemberDefinition.cs new file mode 100644 index 000000000..09878f78f --- /dev/null +++ b/Mono.Cecil/IMemberDefinition.cs @@ -0,0 +1,100 @@ +// +// IMemberDefinition.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace Mono.Cecil { + + public interface IMemberDefinition : ICustomAttributeProvider { + + string Name { get; set; } + string FullName { get; } + + bool IsSpecialName { get; set; } + bool IsRuntimeSpecialName { get; set; } + + TypeDefinition DeclaringType { get; set; } + } + + static partial class Mixin { + + public static bool GetAttributes (this uint self, uint attributes) + { + return (self & attributes) != 0; + } + + public static uint SetAttributes (this uint self, uint attributes, bool value) + { + if (value) + return self | attributes; + + return self & ~attributes; + } + + public static bool GetMaskedAttributes (this uint self, uint mask, uint attributes) + { + return (self & mask) == attributes; + } + + public static uint SetMaskedAttributes (this uint self, uint mask, uint attributes, bool value) + { + if (value) { + self &= ~mask; + return self | attributes; + } + + return self & ~(mask & attributes); + } + + public static bool GetAttributes (this ushort self, ushort attributes) + { + return (self & attributes) != 0; + } + + public static ushort SetAttributes (this ushort self, ushort attributes, bool value) + { + if (value) + return (ushort) (self | attributes); + + return (ushort) (self & ~attributes); + } + + public static bool GetMaskedAttributes (this ushort self, ushort mask, uint attributes) + { + return (self & mask) == attributes; + } + + public static ushort SetMaskedAttributes (this ushort self, ushort mask, uint attributes, bool value) + { + if (value) { + self = (ushort) (self & ~mask); + return (ushort) (self | attributes); + } + + return (ushort) (self & ~(mask & attributes)); + } + } +} diff --git a/Mono.Cecil/IMetadataScope.cs b/Mono.Cecil/IMetadataScope.cs new file mode 100644 index 000000000..f0ab506e5 --- /dev/null +++ b/Mono.Cecil/IMetadataScope.cs @@ -0,0 +1,41 @@ +// +// IMetadataScope.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace Mono.Cecil { + + public enum MetadataScopeType { + AssemblyNameReference, + ModuleReference, + ModuleDefinition, + } + + public interface IMetadataScope : IMetadataTokenProvider { + MetadataScopeType MetadataScopeType { get; } + string Name { get; set; } + } +} diff --git a/Mono.Cecil/IMetadataTokenProvider.cs b/Mono.Cecil/IMetadataTokenProvider.cs new file mode 100644 index 000000000..ff7772481 --- /dev/null +++ b/Mono.Cecil/IMetadataTokenProvider.cs @@ -0,0 +1,35 @@ +// +// IMetadataTokenProvider.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace Mono.Cecil { + + public interface IMetadataTokenProvider { + + MetadataToken MetadataToken { get; set; } + } +} diff --git a/Mono.Cecil/IMethodSignature.cs b/Mono.Cecil/IMethodSignature.cs new file mode 100644 index 000000000..6bae56adc --- /dev/null +++ b/Mono.Cecil/IMethodSignature.cs @@ -0,0 +1,70 @@ +// +// IMethodSignature.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System.Text; + +using Mono.Collections.Generic; + +namespace Mono.Cecil { + + public interface IMethodSignature : IMetadataTokenProvider { + + bool HasThis { get; set; } + bool ExplicitThis { get; set; } + MethodCallingConvention CallingConvention { get; set; } + + bool HasParameters { get; } + Collection Parameters { get; } + TypeReference ReturnType { get; set; } + MethodReturnType MethodReturnType { get; } + } + + static partial class Mixin { + + public static void MethodSignatureFullName (this IMethodSignature self, StringBuilder builder) + { + builder.Append ("("); + + if (self.HasParameters) { + var parameters = self.Parameters; + for (int i = 0; i < parameters.Count; i++) { + var parameter = parameters [i]; + if (i > 0) + builder.Append (","); + + if (parameter.ParameterType.IsSentinel) + builder.Append ("...,"); + + builder.Append (parameter.ParameterType.FullName); + } + } + + builder.Append (")"); + } + } +} diff --git a/Mono.Cecil/Import.cs b/Mono.Cecil/Import.cs new file mode 100644 index 000000000..93e700e8a --- /dev/null +++ b/Mono.Cecil/Import.cs @@ -0,0 +1,566 @@ +// +// Import.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Generic; +using SR = System.Reflection; + +using Mono.Cecil.Metadata; + +namespace Mono.Cecil { + + enum ImportGenericKind { + Definition, + Open, + } + + class MetadataImporter { + + readonly ModuleDefinition module; + + public MetadataImporter (ModuleDefinition module) + { + this.module = module; + } + +#if !CF + static readonly Dictionary type_etype_mapping = new Dictionary (18) { + { typeof (void), ElementType.Void }, + { typeof (bool), ElementType.Boolean }, + { typeof (char), ElementType.Char }, + { typeof (sbyte), ElementType.I1 }, + { typeof (byte), ElementType.U1 }, + { typeof (short), ElementType.I2 }, + { typeof (ushort), ElementType.U2 }, + { typeof (int), ElementType.I4 }, + { typeof (uint), ElementType.U4 }, + { typeof (long), ElementType.I8 }, + { typeof (ulong), ElementType.U8 }, + { typeof (float), ElementType.R4 }, + { typeof (double), ElementType.R8 }, + { typeof (string), ElementType.String }, + { typeof (TypedReference), ElementType.TypedByRef }, + { typeof (IntPtr), ElementType.I }, + { typeof (UIntPtr), ElementType.U }, + { typeof (object), ElementType.Object }, + }; + + public TypeReference ImportType (Type type, IGenericContext context) + { + return ImportType (type, context, ImportGenericKind.Open); + } + + public TypeReference ImportType (Type type, IGenericContext context, ImportGenericKind import_kind) + { + if (IsTypeSpecification (type) || ImportOpenGenericType (type, import_kind)) + return ImportTypeSpecification (type, context); + + var reference = new TypeReference ( + string.Empty, + type.Name, + module, + ImportScope (type.Assembly), + type.IsValueType); + + reference.etype = ImportElementType (type); + + if (IsNestedType (type)) + reference.DeclaringType = ImportType (type.DeclaringType, context, import_kind); + else + reference.Namespace = type.Namespace; + + if (type.IsGenericType) + ImportGenericParameters (reference, type.GetGenericArguments ()); + + return reference; + } + + static bool ImportOpenGenericType (Type type, ImportGenericKind import_kind) + { + return type.IsGenericType && type.IsGenericTypeDefinition && import_kind == ImportGenericKind.Open; + } + + static bool ImportOpenGenericMethod (SR.MethodBase method, ImportGenericKind import_kind) + { + return method.IsGenericMethod && method.IsGenericMethodDefinition && import_kind == ImportGenericKind.Open; + } + + static bool IsNestedType (Type type) + { +#if !SILVERLIGHT + return type.IsNested; +#else + return type.DeclaringType != null; +#endif + } + + TypeReference ImportTypeSpecification (Type type, IGenericContext context) + { + if (type.IsByRef) + return new ByReferenceType (ImportType (type.GetElementType (), context)); + + if (type.IsPointer) + return new PointerType (ImportType (type.GetElementType (), context)); + + if (type.IsArray) + return new ArrayType (ImportType (type.GetElementType (), context), type.GetArrayRank ()); + + if (type.IsGenericType) + return ImportGenericInstance (type, context); + + if (type.IsGenericParameter) + return ImportGenericParameter (type, context); + + throw new NotSupportedException (type.FullName); + } + + static TypeReference ImportGenericParameter (Type type, IGenericContext context) + { + if (context == null) + throw new InvalidOperationException (); + + var owner = type.DeclaringMethod != null + ? context.Method + : context.Type; + + if (owner == null) + throw new InvalidOperationException (); + + return owner.GenericParameters [type.GenericParameterPosition]; + } + + TypeReference ImportGenericInstance (Type type, IGenericContext context) + { + var element_type = ImportType (type.GetGenericTypeDefinition (), context, ImportGenericKind.Definition); + var instance = new GenericInstanceType (element_type); + var arguments = type.GetGenericArguments (); + var instance_arguments = instance.GenericArguments; + + for (int i = 0; i < arguments.Length; i++) + instance_arguments.Add (ImportType (arguments [i], context ?? element_type)); + + return instance; + } + + static bool IsTypeSpecification (Type type) + { + return type.HasElementType + || IsGenericInstance (type) + || type.IsGenericParameter; + } + + static bool IsGenericInstance (Type type) + { + return type.IsGenericType && !type.IsGenericTypeDefinition; + } + + static ElementType ImportElementType (Type type) + { + ElementType etype; + if (!type_etype_mapping.TryGetValue (type, out etype)) + return ElementType.None; + + return etype; + } + + AssemblyNameReference ImportScope (SR.Assembly assembly) + { + AssemblyNameReference scope; +#if !SILVERLIGHT + var name = assembly.GetName (); + + if (TryGetAssemblyNameReference (name, out scope)) + return scope; + + scope = new AssemblyNameReference (name.Name, name.Version) { + Culture = name.CultureInfo.Name, + PublicKeyToken = name.GetPublicKeyToken (), + HashAlgorithm = (AssemblyHashAlgorithm) name.HashAlgorithm, + }; + + module.AssemblyReferences.Add (scope); + + return scope; +#else + var name = AssemblyNameReference.Parse (assembly.FullName); + + if (TryGetAssemblyNameReference (name, out scope)) + return scope; + + module.AssemblyReferences.Add (name); + + return name; +#endif + } + +#if !SILVERLIGHT + bool TryGetAssemblyNameReference (SR.AssemblyName name, out AssemblyNameReference assembly_reference) + { + var references = module.AssemblyReferences; + + for (int i = 0; i < references.Count; i++) { + var reference = references [i]; + if (name.FullName != reference.FullName) // TODO compare field by field + continue; + + assembly_reference = reference; + return true; + } + + assembly_reference = null; + return false; + } +#endif + + public FieldReference ImportField (SR.FieldInfo field, IGenericContext context) + { + var declaring_type = ImportType (field.DeclaringType, context); + + if (IsGenericInstance (field.DeclaringType)) + field = ResolveFieldDefinition (field); + + return new FieldReference { + Name = field.Name, + DeclaringType = declaring_type, + FieldType = ImportType (field.FieldType, context ?? declaring_type), + }; + } + + static SR.FieldInfo ResolveFieldDefinition (SR.FieldInfo field) + { +#if !SILVERLIGHT + return field.Module.ResolveField (field.MetadataToken); +#else + return field.DeclaringType.GetGenericTypeDefinition ().GetField (field.Name, + SR.BindingFlags.Public + | SR.BindingFlags.NonPublic + | (field.IsStatic ? SR.BindingFlags.Static : SR.BindingFlags.Instance)); +#endif + } + + public MethodReference ImportMethod (SR.MethodBase method, IGenericContext context, ImportGenericKind import_kind) + { + if (IsMethodSpecification (method) || ImportOpenGenericMethod (method, import_kind)) + return ImportMethodSpecification (method, context); + + var declaring_type = ImportType (method.DeclaringType, context); + + if (IsGenericInstance (method.DeclaringType)) + method = method.Module.ResolveMethod (method.MetadataToken); + + var reference = new MethodReference { + Name = method.Name, + HasThis = HasCallingConvention (method, SR.CallingConventions.HasThis), + ExplicitThis = HasCallingConvention (method, SR.CallingConventions.ExplicitThis), + DeclaringType = ImportType (method.DeclaringType, context, ImportGenericKind.Definition), + }; + + if (HasCallingConvention (method, SR.CallingConventions.VarArgs)) + reference.CallingConvention &= MethodCallingConvention.VarArg; + + if (method.IsGenericMethod) + ImportGenericParameters (reference, method.GetGenericArguments ()); + + var method_info = method as SR.MethodInfo; + reference.ReturnType = method_info != null + ? ImportType (method_info.ReturnType, context ?? reference) + : ImportType (typeof (void), null); + + var parameters = method.GetParameters (); + var reference_parameters = reference.Parameters; + + for (int i = 0; i < parameters.Length; i++) + reference_parameters.Add ( + new ParameterDefinition (ImportType (parameters [i].ParameterType, context ?? reference))); + + reference.DeclaringType = declaring_type; + + return reference; + } + + static void ImportGenericParameters (IGenericParameterProvider provider, Type [] arguments) + { + var provider_parameters = provider.GenericParameters; + + for (int i = 0; i < arguments.Length; i++) + provider_parameters.Add (new GenericParameter (arguments [i].Name, provider)); + } + + static bool IsMethodSpecification (SR.MethodBase method) + { + return method.IsGenericMethod && !method.IsGenericMethodDefinition; + } + + MethodReference ImportMethodSpecification (SR.MethodBase method, IGenericContext context) + { + var method_info = method as SR.MethodInfo; + if (method_info == null) + throw new InvalidOperationException (); + + var element_method = ImportMethod (method_info.GetGenericMethodDefinition (), context, ImportGenericKind.Definition); + var instance = new GenericInstanceMethod (element_method); + var arguments = method.GetGenericArguments (); + var instance_arguments = instance.GenericArguments; + + for (int i = 0; i < arguments.Length; i++) + instance_arguments.Add (ImportType (arguments [i], context ?? element_method)); + + return instance; + } + + static bool HasCallingConvention (SR.MethodBase method, SR.CallingConventions conventions) + { + return (method.CallingConvention & conventions) != 0; + } +#endif + + public TypeReference ImportType (TypeReference type, IGenericContext context) + { + if (type.IsTypeSpecification ()) + return ImportTypeSpecification (type, context); + + var reference = new TypeReference ( + type.Namespace, + type.Name, + module, + ImportScope (type.Scope), + type.IsValueType); + + MetadataSystem.TryProcessPrimitiveType (reference); + + if (type.IsNested) + reference.DeclaringType = ImportType (type.DeclaringType, context); + + if (type.HasGenericParameters) + ImportGenericParameters (reference, type); + + return reference; + } + + IMetadataScope ImportScope (IMetadataScope scope) + { + switch (scope.MetadataScopeType) { + case MetadataScopeType.AssemblyNameReference: + return ImportAssemblyName ((AssemblyNameReference) scope); + case MetadataScopeType.ModuleDefinition: + return ImportAssemblyName (((ModuleDefinition) scope).Assembly.Name); + case MetadataScopeType.ModuleReference: + throw new NotImplementedException (); + } + + throw new NotSupportedException (); + } + + AssemblyNameReference ImportAssemblyName (AssemblyNameReference name) + { + AssemblyNameReference reference; + if (TryGetAssemblyNameReference (name, out reference)) + return reference; + + reference = new AssemblyNameReference (name.Name, name.Version) { + Culture = name.Culture, + HashAlgorithm = name.HashAlgorithm, + }; + + var pk_token = !name.PublicKeyToken.IsNullOrEmpty () + ? new byte [name.PublicKeyToken.Length] + : Empty.Array; + + if (pk_token.Length > 0) + Buffer.BlockCopy (name.PublicKeyToken, 0, pk_token, 0, pk_token.Length); + + reference.PublicKeyToken = pk_token; + + module.AssemblyReferences.Add (reference); + + return reference; + } + + bool TryGetAssemblyNameReference (AssemblyNameReference name_reference, out AssemblyNameReference assembly_reference) + { + var references = module.AssemblyReferences; + + for (int i = 0; i < references.Count; i++) { + var reference = references [i]; + if (name_reference.FullName != reference.FullName) // TODO compare field by field + continue; + + assembly_reference = reference; + return true; + } + + assembly_reference = null; + return false; + } + + static void ImportGenericParameters (IGenericParameterProvider imported, IGenericParameterProvider original) + { + var parameters = original.GenericParameters; + var imported_parameters = imported.GenericParameters; + + for (int i = 0; i < parameters.Count; i++) + imported_parameters.Add (new GenericParameter (parameters [i].Name, imported)); + } + + TypeReference ImportTypeSpecification (TypeReference type, IGenericContext context) + { + switch (type.etype) { + case ElementType.SzArray: + var vector = (ArrayType) type; + return new ArrayType (ImportType (vector.ElementType, context)); + case ElementType.Ptr: + var pointer = (PointerType) type; + return new PointerType (ImportType (pointer.ElementType, context)); + case ElementType.ByRef: + var byref = (ByReferenceType) type; + return new ByReferenceType (ImportType (byref.ElementType, context)); + case ElementType.Pinned: + var pinned = (PinnedType) type; + return new PinnedType (ImportType (pinned.ElementType, context)); + case ElementType.Sentinel: + var sentinel = (SentinelType) type; + return new SentinelType (ImportType (sentinel.ElementType, context)); + case ElementType.CModOpt: + var modopt = (OptionalModifierType) type; + return new OptionalModifierType ( + ImportType (modopt.ModifierType, context), + ImportType (modopt.ElementType, context)); + case ElementType.CModReqD: + var modreq = (RequiredModifierType) type; + return new RequiredModifierType ( + ImportType (modreq.ModifierType, context), + ImportType (modreq.ElementType, context)); + case ElementType.Array: + var array = (ArrayType) type; + var imported_array = new ArrayType (ImportType (array.ElementType, context)); + if (array.IsVector) + return imported_array; + + var dimensions = array.Dimensions; + var imported_dimensions = imported_array.Dimensions; + + imported_dimensions.Clear (); + + for (int i = 0; i < dimensions.Count; i++) { + var dimension = dimensions [i]; + + imported_dimensions.Add (new ArrayDimension (dimension.LowerBound, dimension.UpperBound)); + } + + return imported_array; + case ElementType.GenericInst: + var instance = (GenericInstanceType) type; + var element_type = ImportType (instance.ElementType, context); + var imported_instance = new GenericInstanceType (element_type); + + var arguments = instance.GenericArguments; + var imported_arguments = imported_instance.GenericArguments; + + for (int i = 0; i < arguments.Count; i++) + imported_arguments.Add (ImportType (arguments [i], context)); + + return imported_instance; + case ElementType.Var: + if (context == null || context.Type == null) + throw new InvalidOperationException (); + + return ((TypeReference) context.Type).GetElementType ().GenericParameters [((GenericParameter) type).Position]; + case ElementType.MVar: + if (context == null || context.Method == null) + throw new InvalidOperationException (); + + return context.Method.GenericParameters [((GenericParameter) type).Position]; + } + + throw new NotSupportedException (type.etype.ToString ()); + } + + public FieldReference ImportField (FieldReference field, IGenericContext context) + { + var declaring_type = ImportType (field.DeclaringType, context); + + return new FieldReference { + Name = field.Name, + DeclaringType = declaring_type, + FieldType = ImportType (field.FieldType, context ?? declaring_type), + }; + } + + public MethodReference ImportMethod (MethodReference method, IGenericContext context) + { + if (method.IsGenericInstance) + return ImportMethodSpecification (method, context); + + var declaring_type = ImportType (method.DeclaringType, context); + + var reference = new MethodReference { + Name = method.Name, + HasThis = method.HasThis, + ExplicitThis = method.ExplicitThis, + DeclaringType = declaring_type, + }; + + reference.CallingConvention = method.CallingConvention; + + if (method.HasGenericParameters) + ImportGenericParameters (reference, method); + + reference.ReturnType = ImportType (method.ReturnType, context ?? reference); + + if (!method.HasParameters) + return reference; + + var reference_parameters = reference.Parameters; + + var parameters = method.Parameters; + for (int i = 0; i < parameters.Count; i++) + reference_parameters.Add ( + new ParameterDefinition (ImportType (parameters [i].ParameterType, context ?? reference))); + + return reference; + } + + MethodSpecification ImportMethodSpecification (MethodReference method, IGenericContext context) + { + if (!method.IsGenericInstance) + throw new NotSupportedException (); + + var instance = (GenericInstanceMethod) method; + var element_method = ImportMethod (instance.ElementMethod, context); + var imported_instance = new GenericInstanceMethod (element_method); + + var arguments = instance.GenericArguments; + var imported_arguments = imported_instance.GenericArguments; + + for (int i = 0; i < arguments.Count; i++) + imported_arguments.Add (ImportType (arguments [i], context)); + + return imported_instance; + } + } +} diff --git a/Mono.Cecil/LinkedResource.cs b/Mono.Cecil/LinkedResource.cs new file mode 100644 index 000000000..a5530fc13 --- /dev/null +++ b/Mono.Cecil/LinkedResource.cs @@ -0,0 +1,60 @@ +// +// LinkedResource.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace Mono.Cecil { + + public sealed class LinkedResource : Resource { + + internal byte [] hash; + string file; + + public byte [] Hash { + get { return hash; } + } + + public string File { + get { return file; } + set { file = value; } + } + + public override ResourceType ResourceType { + get { return ResourceType.Linked; } + } + + public LinkedResource (string name, ManifestResourceAttributes flags) + : base (name, flags) + { + } + + public LinkedResource (string name, ManifestResourceAttributes flags, string file) + : base (name, flags) + { + this.file = file; + } + } +} diff --git a/Mono.Cecil/ManifestResourceAttributes.cs b/Mono.Cecil/ManifestResourceAttributes.cs new file mode 100644 index 000000000..d72d1d0c7 --- /dev/null +++ b/Mono.Cecil/ManifestResourceAttributes.cs @@ -0,0 +1,39 @@ +// +// ManifestResourceAttributes.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace Mono.Cecil { + + [Flags] + public enum ManifestResourceAttributes : uint { + VisibilityMask = 0x0007, + Public = 0x0001, // The resource is exported from the Assembly + Private = 0x0002 // The resource is private to the Assembly + } +} diff --git a/Mono.Cecil/MarshalInfo.cs b/Mono.Cecil/MarshalInfo.cs new file mode 100644 index 000000000..1fce23a8d --- /dev/null +++ b/Mono.Cecil/MarshalInfo.cs @@ -0,0 +1,171 @@ +// +// MarshalInfo.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace Mono.Cecil { + + public class MarshalInfo { + + internal NativeType native; + + public NativeType NativeType { + get { return native; } + set { native = value; } + } + + public MarshalInfo (NativeType native) + { + this.native = native; + } + } + + public sealed class ArrayMarshalInfo : MarshalInfo { + + internal NativeType element_type; + internal int size_parameter_index; + internal int size; + internal int size_parameter_multiplier; + + public NativeType ElementType { + get { return element_type; } + set { element_type = value; } + } + + public int SizeParameterIndex { + get { return size_parameter_index; } + set { size_parameter_index = value; } + } + + public int Size { + get { return size; } + set { size = value; } + } + + public int SizeParameterMultiplier { + get { return size_parameter_multiplier; } + set { size_parameter_multiplier = value; } + } + + public ArrayMarshalInfo () + : base (NativeType.Array) + { + element_type = NativeType.None; + size_parameter_index = -1; + size = -1; + size_parameter_multiplier = -1; + } + } + + public sealed class CustomMarshalInfo : MarshalInfo { + + internal Guid guid; + internal string unmanaged_type; + internal TypeReference managed_type; + internal string cookie; + + public Guid Guid { + get { return guid; } + set { guid = value; } + } + + public string UnmanagedType { + get { return unmanaged_type; } + set { unmanaged_type = value; } + } + + public TypeReference ManagedType { + get { return managed_type; } + set { managed_type = value; } + } + + public string Cookie { + get { return cookie; } + set { cookie = value; } + } + + public CustomMarshalInfo () + : base (NativeType.CustomMarshaler) + { + } + } + + public sealed class SafeArrayMarshalInfo : MarshalInfo { + + internal VariantType element_type; + + public VariantType ElementType { + get { return element_type; } + set { element_type = value; } + } + + public SafeArrayMarshalInfo () + : base (NativeType.SafeArray) + { + element_type = VariantType.None; + } + } + + public sealed class FixedArrayMarshalInfo : MarshalInfo { + + internal NativeType element_type; + internal int size; + + public NativeType ElementType { + get { return element_type; } + set { element_type = value; } + } + + public int Size { + get { return size; } + set { size = value; } + } + + public FixedArrayMarshalInfo () + : base (NativeType.FixedArray) + { + element_type = NativeType.None; + } + } + + public sealed class FixedSysStringMarshalInfo : MarshalInfo { + + internal int size; + + public int Size { + get { return size; } + set { size = value; } + } + + public FixedSysStringMarshalInfo () + : base (NativeType.FixedSysString) + { + size = -1; + } + } +} diff --git a/Mono.Cecil/MemberDefinitionCollection.cs b/Mono.Cecil/MemberDefinitionCollection.cs new file mode 100644 index 000000000..1e703026e --- /dev/null +++ b/Mono.Cecil/MemberDefinitionCollection.cs @@ -0,0 +1,92 @@ +// +// MemberDefinitionCollection.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +using Mono.Collections.Generic; + +namespace Mono.Cecil { + + class MemberDefinitionCollection : Collection where T : IMemberDefinition { + + TypeDefinition container; + + internal MemberDefinitionCollection (TypeDefinition container) + { + this.container = container; + } + + internal MemberDefinitionCollection (TypeDefinition container, int capacity) + : base (capacity) + { + this.container = container; + } + + protected override void OnAdd (T item, int index) + { + Attach (item); + } + + protected sealed override void OnSet (T item, int index) + { + Attach (item); + } + + protected sealed override void OnInsert (T item, int index) + { + Attach (item); + } + + protected sealed override void OnRemove (T item, int index) + { + Detach (item); + } + + protected sealed override void OnClear () + { + foreach (var definition in this) + Detach (definition); + } + + void Attach (T element) + { + if (element.DeclaringType == container) + return; + + if (element.DeclaringType != null) + throw new ArgumentException ("Member already attached"); + + element.DeclaringType = this.container; + } + + static void Detach (T element) + { + element.DeclaringType = null; + } + } +} diff --git a/Mono.Cecil/MemberReference.cs b/Mono.Cecil/MemberReference.cs new file mode 100644 index 000000000..b3edf3997 --- /dev/null +++ b/Mono.Cecil/MemberReference.cs @@ -0,0 +1,101 @@ +// +// MemberReference.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace Mono.Cecil { + + public abstract class MemberReference : IMetadataTokenProvider { + + string name; + TypeReference declaring_type; + + internal MetadataToken token; + + public virtual string Name { + get { return name; } + set { name = value; } + } + + public abstract string FullName { + get; + } + + public virtual TypeReference DeclaringType { + get { return declaring_type; } + set { declaring_type = value; } + } + + public MetadataToken MetadataToken { + get { return token; } + set { token = value; } + } + + internal bool HasImage { + get { + var module = Module; + if (module == null) + return false; + + return module.HasImage; + } + } + + public virtual ModuleDefinition Module { + get { return declaring_type != null ? declaring_type.Module : null; } + } + + public virtual bool IsDefinition { + get { return false; } + } + + internal virtual bool ContainsGenericParameter { + get { return declaring_type != null && declaring_type.ContainsGenericParameter; } + } + + internal MemberReference () + { + } + + internal MemberReference (string name) + { + this.name = name ?? string.Empty; + } + + internal string MemberFullName () + { + if (declaring_type == null) + return name; + + return declaring_type.FullName + "::" + name; + } + + public override string ToString () + { + return FullName; + } + } +} diff --git a/Mono.Cecil/MetadataResolver.cs b/Mono.Cecil/MetadataResolver.cs new file mode 100644 index 000000000..a2b76c74f --- /dev/null +++ b/Mono.Cecil/MetadataResolver.cs @@ -0,0 +1,313 @@ +// +// MetadataResolver.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Generic; + +using Mono.Collections.Generic; + +namespace Mono.Cecil { + + public interface IAssemblyResolver { + AssemblyDefinition Resolve (AssemblyNameReference name); + AssemblyDefinition Resolve (AssemblyNameReference name, ReaderParameters parameters); + + AssemblyDefinition Resolve (string fullName); + AssemblyDefinition Resolve (string fullName, ReaderParameters parameters); + } + + public class ResolutionException : Exception { + + readonly MemberReference member; + + public MemberReference Member { + get { return member; } + } + + public ResolutionException (MemberReference member) + : base ("Failed to resolve " + member.FullName) + { + this.member = member; + } + } + + static class MetadataResolver { + + public static TypeDefinition Resolve (IAssemblyResolver resolver, TypeReference type) + { + type = type.GetElementType (); + + var scope = type.Scope; + switch (scope.MetadataScopeType) { + case MetadataScopeType.AssemblyNameReference: + var assembly = resolver.Resolve ((AssemblyNameReference) scope); + if (assembly == null) + return null; + + return GetType (resolver, assembly.MainModule, type); + case MetadataScopeType.ModuleDefinition: + return GetType (resolver, (ModuleDefinition) scope, type); + case MetadataScopeType.ModuleReference: + var modules = type.Module.Assembly.Modules; + var module_ref = (ModuleReference) scope; + for (int i = 0; i < modules.Count; i++) { + var netmodule = modules [i]; + if (netmodule.Name == module_ref.Name) + return GetType (resolver, netmodule, type); + } + break; + } + + throw new NotSupportedException (); + } + + static TypeDefinition GetType (IAssemblyResolver resolver, ModuleDefinition module, TypeReference reference) + { + var type = GetType (module, reference); + if (type != null) + return type; + + if (!module.HasExportedTypes) + return null; + + var exported_types = module.ExportedTypes; + + for (int i = 0; i < exported_types.Count; i++) { + var exported_type = exported_types [i]; + if (exported_type.Name != reference.Name) + continue; + + if (exported_type.Namespace != reference.Namespace) + continue; + + return exported_type.Resolve (); + } + + return null; + } + + static TypeDefinition GetType (ModuleDefinition module, TypeReference type) + { + if (!type.IsNested) + return module.GetType (type.Namespace, type.Name); + + var declaring_type = type.DeclaringType.Resolve (); + if (declaring_type == null) + return null; + + return declaring_type.GetNestedType (type.Name); + } + + public static FieldDefinition Resolve (IAssemblyResolver resolver, FieldReference field) + { + var type = Resolve (resolver, field.DeclaringType); + if (type == null) + return null; + + if (!type.HasFields) + return null; + + return GetField (resolver, type, field); + } + + static FieldDefinition GetField (IAssemblyResolver resolver, TypeDefinition type, FieldReference reference) + { + while (type != null) { + var field = GetField (type.Fields, reference); + if (field != null) + return field; + + if (type.BaseType == null) + return null; + + type = Resolve (resolver, type.BaseType); + } + + return null; + } + + static FieldDefinition GetField (IList fields, FieldReference reference) + { + for (int i = 0; i < fields.Count; i++) { + var field = fields [i]; + + if (field.Name != reference.Name) + continue; + + if (!AreSame (field.FieldType, reference.FieldType)) + continue; + + return field; + } + + return null; + } + + public static MethodDefinition Resolve (IAssemblyResolver resolver, MethodReference method) + { + var type = Resolve (resolver, method.DeclaringType); + if (type == null) + return null; + + method = method.GetElementMethod (); + + if (!type.HasMethods) + return null; + + return GetMethod (resolver, type, method); + } + + static MethodDefinition GetMethod (IAssemblyResolver resolver, TypeDefinition type, MethodReference reference) + { + while (type != null) { + var method = GetMethod (type.Methods, reference); + if (method != null) + return method; + + if (type.BaseType == null) + return null; + + type = Resolve (resolver, type.BaseType); + } + + return null; + } + + public static MethodDefinition GetMethod (IList methods, MethodReference reference) + { + for (int i = 0; i < methods.Count; i++) { + var method = methods [i]; + + if (method.Name != reference.Name) + continue; + + if (!AreSame (method.ReturnType, reference.ReturnType)) + continue; + + if (method.HasParameters != reference.HasParameters) + continue; + + if (!method.HasParameters && !reference.HasParameters) + return method; + + if (!AreSame (method.Parameters, reference.Parameters)) + continue; + + return method; + } + + return null; + } + + static bool AreSame (Collection a, Collection b) + { + var count = a.Count; + + if (count != b.Count) + return false; + + if (count == 0) + return true; + + for (int i = 0; i < count; i++) + if (!AreSame (a [i].ParameterType, b [i].ParameterType)) + return false; + + return true; + } + + static bool AreSame (TypeSpecification a, TypeSpecification b) + { + if (!AreSame (a.ElementType, b.ElementType)) + return false; + + if (a.IsGenericInstance) + return AreSame ((GenericInstanceType) a, (GenericInstanceType) b); + + if (a.IsRequiredModifier || a.IsOptionalModifier) + return AreSame ((IModifierType) a, (IModifierType) b); + + if (a.IsArray) + return AreSame ((ArrayType) a, (ArrayType) b); + + return true; + } + + static bool AreSame (ArrayType a, ArrayType b) + { + if (a.Rank != b.Rank) + return false; + + // TODO: dimensions + + return true; + } + + static bool AreSame (IModifierType a, IModifierType b) + { + return AreSame (a.ModifierType, b.ModifierType); + } + + static bool AreSame (GenericInstanceType a, GenericInstanceType b) + { + if (!a.HasGenericArguments) + return !b.HasGenericArguments; + + if (!b.HasGenericArguments) + return false; + + if (a.GenericArguments.Count != b.GenericArguments.Count) + return false; + + for (int i = 0; i < a.GenericArguments.Count; i++) + if (!AreSame (a.GenericArguments [i], b.GenericArguments [i])) + return false; + + return true; + } + + static bool AreSame (GenericParameter a, GenericParameter b) + { + return a.Position == b.Position; + } + + static bool AreSame (TypeReference a, TypeReference b) + { + if (a.etype != b.etype) + return false; + + if (a.IsGenericParameter) + return AreSame ((GenericParameter) a, (GenericParameter) b); + + if (a.IsTypeSpecification ()) + return AreSame ((TypeSpecification) a, (TypeSpecification) b); + + return a.FullName == b.FullName; + } + } +} diff --git a/Mono.Cecil/MetadataSystem.cs b/Mono.Cecil/MetadataSystem.cs new file mode 100644 index 000000000..4d65674e8 --- /dev/null +++ b/Mono.Cecil/MetadataSystem.cs @@ -0,0 +1,380 @@ +// +// MetadataSystem.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Generic; + +using Mono.Cecil.Metadata; + +namespace Mono.Cecil { + + struct Range { + public uint Start; + public uint Length; + + public Range (uint index, uint length) + { + this.Start = index; + this.Length = length; + } + } + + sealed class MetadataSystem { + + internal AssemblyNameReference [] AssemblyReferences; + internal ModuleReference [] ModuleReferences; + + internal TypeDefinition [] Types; + internal TypeReference [] TypeReferences; + + internal FieldDefinition [] Fields; + internal MethodDefinition [] Methods; + internal MemberReference [] MemberReferences; + + internal Dictionary NestedTypes; + internal Dictionary ReverseNestedTypes; + internal Dictionary Interfaces; + internal Dictionary> ClassLayouts; + internal Dictionary FieldLayouts; + internal Dictionary FieldRVAs; + internal Dictionary FieldMarshals; + internal Dictionary> Constants; + internal Dictionary Overrides; + internal Dictionary CustomAttributes; + internal Dictionary SecurityDeclarations; + internal Dictionary Events; + internal Dictionary Properties; + internal Dictionary> Semantics; + internal Dictionary> PInvokes; + internal Dictionary GenericParameters; + internal Dictionary GenericConstraints; + + static Dictionary> primitive_value_types; + + static void InitializePrimitives () + { + primitive_value_types = new Dictionary> (18) { + { "Void", new Row (ElementType.Void, false) }, + { "Boolean", new Row (ElementType.Boolean, true) }, + { "Char", new Row (ElementType.Char, true) }, + { "SByte", new Row (ElementType.I1, true) }, + { "Byte", new Row (ElementType.U1, true) }, + { "Int16", new Row (ElementType.I2, true) }, + { "UInt16", new Row (ElementType.U2, true) }, + { "Int32", new Row (ElementType.I4, true) }, + { "UInt32", new Row (ElementType.U4, true) }, + { "Int64", new Row (ElementType.I8, true) }, + { "UInt64", new Row (ElementType.U8, true) }, + { "Single", new Row (ElementType.R4, true) }, + { "Double", new Row (ElementType.R8, true) }, + { "String", new Row (ElementType.String, false) }, + { "TypedReference", new Row (ElementType.TypedByRef, false) }, + { "IntPtr", new Row (ElementType.I, true) }, + { "UIntPtr", new Row (ElementType.U, true) }, + { "Object", new Row (ElementType.Object, false) }, + }; + } + + public static void TryProcessPrimitiveType (TypeReference type) + { + var scope = type.scope; + if (scope == null) + return; + + if (scope.MetadataScopeType != MetadataScopeType.AssemblyNameReference) + return; + + if (scope.Name != "mscorlib") + return; + + if (type.Namespace != "System") + return; + + if (primitive_value_types == null) + InitializePrimitives (); + + Row primitive_data; + if (!primitive_value_types.TryGetValue (type.Name, out primitive_data)) + return; + + type.etype = primitive_data.Col1; + type.IsValueType = primitive_data.Col2; + } + + public void Clear () + { + if (NestedTypes != null) NestedTypes.Clear (); + if (ReverseNestedTypes != null) ReverseNestedTypes.Clear (); + if (Interfaces != null) Interfaces.Clear (); + if (ClassLayouts != null) ClassLayouts.Clear (); + if (FieldLayouts != null) FieldLayouts.Clear (); + if (FieldRVAs != null) FieldRVAs.Clear (); + if (FieldMarshals != null) FieldMarshals.Clear (); + if (Constants != null) Constants.Clear (); + if (Overrides != null) Overrides.Clear (); + if (CustomAttributes != null) CustomAttributes.Clear (); + if (SecurityDeclarations != null) SecurityDeclarations.Clear (); + if (Events != null) Events.Clear (); + if (Properties != null) Properties.Clear (); + if (Semantics != null) Semantics.Clear (); + if (PInvokes != null) PInvokes.Clear (); + if (GenericParameters != null) GenericParameters.Clear (); + if (GenericConstraints != null) GenericConstraints.Clear (); + } + + public TypeDefinition GetTypeDefinition (uint rid) + { + if (rid < 1 || rid > Types.Length) + return null; + + return Types [rid - 1]; + } + + public void AddTypeDefinition (TypeDefinition type) + { + Types [type.token.RID - 1] = type; + } + + public TypeReference GetTypeReference (uint rid) + { + if (rid < 1 || rid > TypeReferences.Length) + return null; + + return TypeReferences [rid - 1]; + } + + public void AddTypeReference (TypeReference type) + { + TypeReferences [type.token.RID - 1] = type; + } + + public FieldDefinition GetFieldDefinition (uint rid) + { + if (rid < 1 || rid > Fields.Length) + return null; + + return Fields [rid - 1]; + } + + public void AddFieldDefinition (FieldDefinition field) + { + Fields [field.token.RID - 1] = field; + } + + public MethodDefinition GetMethodDefinition (uint rid) + { + if (rid < 1 || rid > Methods.Length) + return null; + + return Methods [rid - 1]; + } + + public void AddMethodDefinition (MethodDefinition method) + { + Methods [method.token.RID - 1] = method; + } + + public MemberReference GetMemberReference (uint rid) + { + if (rid < 1 || rid > MemberReferences.Length) + return null; + + return MemberReferences [rid - 1]; + } + + public void AddMemberReference (MemberReference member) + { + MemberReferences [member.token.RID - 1] = member; + } + + public bool TryGetNestedTypeMapping (TypeDefinition type, out uint [] mapping) + { + return NestedTypes.TryGetValue (type.token.RID, out mapping); + } + + public void SetNestedTypeMapping (uint type_rid, uint [] mapping) + { + NestedTypes [type_rid] = mapping; + } + + public void RemoveNestedTypeMapping (TypeDefinition type) + { + NestedTypes.Remove (type.token.RID); + } + + public bool TryGetReverseNestedTypeMapping (TypeDefinition type, out uint declaring) + { + return ReverseNestedTypes.TryGetValue (type.token.RID, out declaring); + } + + public void SetReverseNestedTypeMapping (uint nested, uint declaring) + { + ReverseNestedTypes.Add (nested, declaring); + } + + public void RemoveReverseNestedTypeMapping (TypeDefinition type) + { + ReverseNestedTypes.Remove (type.token.RID); + } + + public bool TryGetInterfaceMapping (TypeDefinition type, out MetadataToken [] mapping) + { + return Interfaces.TryGetValue (type.token.RID, out mapping); + } + + public void SetInterfaceMapping (uint type_rid, MetadataToken [] mapping) + { + Interfaces [type_rid] = mapping; + } + + public void RemoveInterfaceMapping (TypeDefinition type) + { + Interfaces.Remove (type.token.RID); + } + + public void AddPropertiesRange (uint type_rid, Range range) + { + Properties.Add (type_rid, range); + } + + public bool TryGetPropertiesRange (TypeDefinition type, out Range range) + { + return Properties.TryGetValue (type.token.RID, out range); + } + + public void RemovePropertiesRange (TypeDefinition type) + { + Properties.Remove (type.token.RID); + } + + public void AddEventsRange (uint type_rid, Range range) + { + Events.Add (type_rid, range); + } + + public bool TryGetEventsRange (TypeDefinition type, out Range range) + { + return Events.TryGetValue (type.token.RID, out range); + } + + public void RemoveEventsRange (TypeDefinition type) + { + Events.Remove (type.token.RID); + } + + public bool TryGetGenericParameterRange (IGenericParameterProvider owner, out Range range) + { + return GenericParameters.TryGetValue (owner.MetadataToken, out range); + } + + public void RemoveGenericParameterRange (IGenericParameterProvider owner) + { + GenericParameters.Remove (owner.MetadataToken); + } + + public bool TryGetCustomAttributeRange (ICustomAttributeProvider owner, out Range range) + { + return CustomAttributes.TryGetValue (owner.MetadataToken, out range); + } + + public void RemoveCustomAttributeRange (ICustomAttributeProvider owner) + { + CustomAttributes.Remove (owner.MetadataToken); + } + + public bool TryGetSecurityDeclarationRange (ISecurityDeclarationProvider owner, out Range range) + { + return SecurityDeclarations.TryGetValue (owner.MetadataToken, out range); + } + + public void RemoveSecurityDeclarationRange (ISecurityDeclarationProvider owner) + { + SecurityDeclarations.Remove (owner.MetadataToken); + } + + public bool TryGetGenericConstraintMapping (GenericParameter generic_parameter, out MetadataToken [] mapping) + { + return GenericConstraints.TryGetValue (generic_parameter.token.RID, out mapping); + } + + public void SetGenericConstraintMapping (uint gp_rid, MetadataToken [] mapping) + { + GenericConstraints [gp_rid] = mapping; + } + + public void RemoveGenericConstraintMapping (GenericParameter generic_parameter) + { + GenericConstraints.Remove (generic_parameter.token.RID); + } + + public bool TryGetOverrideMapping (MethodDefinition method, out MetadataToken [] mapping) + { + return Overrides.TryGetValue (method.token.RID, out mapping); + } + + public void SetOverrideMapping (uint rid, MetadataToken [] mapping) + { + Overrides [rid] = mapping; + } + + public void RemoveOverrideMapping (MethodDefinition method) + { + Overrides.Remove (method.token.RID); + } + + public TypeDefinition GetFieldDeclaringType (uint field_rid) + { + return BinaryRangeSearch (Types, field_rid, true); + } + + public TypeDefinition GetMethodDeclaringType (uint method_rid) + { + return BinaryRangeSearch (Types, method_rid, false); + } + + static TypeDefinition BinaryRangeSearch (TypeDefinition [] types, uint rid, bool field) + { + int min = 0; + int max = types.Length - 1; + while (min <= max) { + int mid = min + ((max - min) / 2); + var type = types [mid]; + var range = field ? type.fields_range : type.methods_range; + + if (rid < range.Start) + max = mid - 1; + else if (rid >= range.Start + range.Length) + min = mid + 1; + else + return type; + } + + return null; + } + } +} diff --git a/Mono.Cecil/MethodAttributes.cs b/Mono.Cecil/MethodAttributes.cs new file mode 100644 index 000000000..3446702b5 --- /dev/null +++ b/Mono.Cecil/MethodAttributes.cs @@ -0,0 +1,66 @@ +// +// MethodAttributes.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace Mono.Cecil { + + [Flags] + public enum MethodAttributes : ushort { + MemberAccessMask = 0x0007, + CompilerControlled = 0x0000, // Member not referenceable + Private = 0x0001, // Accessible only by the parent type + FamANDAssem = 0x0002, // Accessible by sub-types only in this Assembly + Assembly = 0x0003, // Accessibly by anyone in the Assembly + Family = 0x0004, // Accessible only by type and sub-types + FamORAssem = 0x0005, // Accessibly by sub-types anywhere, plus anyone in assembly + Public = 0x0006, // Accessibly by anyone who has visibility to this scope + + Static = 0x0010, // Defined on type, else per instance + Final = 0x0020, // Method may not be overridden + Virtual = 0x0040, // Method is virtual + HideBySig = 0x0080, // Method hides by name+sig, else just by name + + VtableLayoutMask = 0x0100, // Use this mask to retrieve vtable attributes + ReuseSlot = 0x0000, // Method reuses existing slot in vtable + NewSlot = 0x0100, // Method always gets a new slot in the vtable + + CheckAccessOnOverride = 0x0200, // Method can only be overriden if also accessible + Abstract = 0x0400, // Method does not provide an implementation + SpecialName = 0x0800, // Method is special + + // Interop Attributes + PInvokeImpl = 0x2000, // Implementation is forwarded through PInvoke + UnmanagedExport = 0x0008, // Reserved: shall be zero for conforming implementations + + // Additional flags + RTSpecialName = 0x1000, // CLI provides 'special' behavior, depending upon the name of the method + HasSecurity = 0x4000, // Method has security associate with it + RequireSecObject = 0x8000 // Method calls another method containing security code + } +} diff --git a/Mono.Cecil/MethodCallingConvention.cs b/Mono.Cecil/MethodCallingConvention.cs new file mode 100644 index 000000000..c96dc1cf2 --- /dev/null +++ b/Mono.Cecil/MethodCallingConvention.cs @@ -0,0 +1,40 @@ +// +// MethodCallingConvention.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace Mono.Cecil { + + public enum MethodCallingConvention : byte { + Default = 0x0, + C = 0x1, + StdCall = 0x2, + ThisCall = 0x3, + FastCall = 0x4, + VarArg = 0x5, + Generic = 0x10, + } +} diff --git a/Mono.Cecil/MethodDefinition.cs b/Mono.Cecil/MethodDefinition.cs new file mode 100644 index 000000000..3b74e5a7d --- /dev/null +++ b/Mono.Cecil/MethodDefinition.cs @@ -0,0 +1,487 @@ +// +// MethodDefinition.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using Mono.Cecil.Cil; +using Mono.Collections.Generic; + +using RVA = System.UInt32; + +namespace Mono.Cecil { + + public sealed class MethodDefinition : MethodReference, IMemberDefinition, ISecurityDeclarationProvider { + + ushort attributes; + ushort impl_attributes; + internal MethodSemanticsAttributes? sem_attrs; + Collection custom_attributes; + Collection security_declarations; + + internal RVA rva; + internal PInvokeInfo pinvoke; + Collection overrides; + + internal MethodBody body; + + public MethodAttributes Attributes { + get { return (MethodAttributes) attributes; } + set { attributes = (ushort) value; } + } + + public MethodImplAttributes ImplAttributes { + get { return (MethodImplAttributes) impl_attributes; } + set { impl_attributes = (ushort) value; } + } + + public MethodSemanticsAttributes SemanticsAttributes { + get { + if (sem_attrs.HasValue) + return sem_attrs.Value; + + if (HasImage) { + ReadSemantics (); + return sem_attrs.Value; + } + + sem_attrs = MethodSemanticsAttributes.None; + return sem_attrs.Value; + } + set { sem_attrs = value; } + } + + internal void ReadSemantics () + { + if (sem_attrs.HasValue) + return; + + var module = this.Module; + if (module == null) + return; + + if (!module.HasImage) + return; + + module.Read (this, (method, reader) => reader.ReadAllSemantics (method)); + } + + public bool HasSecurityDeclarations { + get { + if (security_declarations != null) + return security_declarations.Count > 0; + + return this.GetHasSecurityDeclarations (Module); + } + } + + public Collection SecurityDeclarations { + get { return security_declarations ?? (security_declarations = this.GetSecurityDeclarations (Module)); } + } + + public bool HasCustomAttributes { + get { + if (custom_attributes != null) + return custom_attributes.Count > 0; + + return this.GetHasCustomAttributes (Module); + } + } + + public Collection CustomAttributes { + get { return custom_attributes ?? (custom_attributes = this.GetCustomAttributes (Module)); } + } + + public int RVA { + get { return (int) rva; } + } + + public bool HasBody { + get { + return (attributes & (ushort) MethodAttributes.Abstract) == 0 && + (attributes & (ushort) MethodAttributes.PInvokeImpl) == 0 && + (impl_attributes & (ushort) MethodImplAttributes.InternalCall) == 0 && + (impl_attributes & (ushort) MethodImplAttributes.Native) == 0 && + (impl_attributes & (ushort) MethodImplAttributes.Unmanaged) == 0 && + (impl_attributes & (ushort) MethodImplAttributes.Runtime) == 0; + } + } + + public MethodBody Body { + get { + if (body != null) + return body; + + if (!HasBody) + return null; + + if (HasImage && rva != 0) + return body = Module.Read (this, (method, reader) => reader.ReadMethodBody (method)); + + return body = new MethodBody (this); + } + set { body = value; } + } + + public bool HasPInvokeInfo { + get { + if (pinvoke != null) + return true; + + return IsPInvokeImpl; + } + } + + public PInvokeInfo PInvokeInfo { + get { + if (pinvoke != null) + return pinvoke; + + if (HasImage && IsPInvokeImpl) + return pinvoke = Module.Read (this, (method, reader) => reader.ReadPInvokeInfo (method)); + + return null; + } + set { + IsPInvokeImpl = true; + pinvoke = value; + } + } + + public bool HasOverrides { + get { + if (overrides != null) + return overrides.Count > 0; + + if (HasImage) + return Module.Read (this, (method, reader) => reader.HasOverrides (method)); + + return false; + } + } + + public Collection Overrides { + get { + if (overrides != null) + return overrides; + + if (HasImage) + return overrides = Module.Read (this, (method, reader) => reader.ReadOverrides (method)); + + return overrides = new Collection (); + } + } + + public override bool HasGenericParameters { + get { + if (generic_parameters != null) + return generic_parameters.Count > 0; + + return this.GetHasGenericParameters (Module); + } + } + + public override Collection GenericParameters { + get { return generic_parameters ?? (generic_parameters = this.GetGenericParameters (Module)); } + } + + #region MethodAttributes + + public bool IsCompilerControlled { + get { return attributes.GetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.CompilerControlled); } + set { attributes = attributes.SetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.CompilerControlled, value); } + } + + public bool IsPrivate { + get { return attributes.GetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.Private); } + set { attributes = attributes.SetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.Private, value); } + } + + public bool IsFamilyAndAssembly { + get { return attributes.GetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.FamANDAssem); } + set { attributes = attributes.SetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.FamANDAssem, value); } + } + + public bool IsAssembly { + get { return attributes.GetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.Assembly); } + set { attributes = attributes.SetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.Assembly, value); } + } + + public bool IsFamily { + get { return attributes.GetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.Family); } + set { attributes = attributes.SetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.Family, value); } + } + + public bool IsFamilyOrAssembly { + get { return attributes.GetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.FamORAssem); } + set { attributes = attributes.SetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.FamORAssem, value); } + } + + public bool IsPublic { + get { return attributes.GetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.Public); } + set { attributes = attributes.SetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.Public, value); } + } + + public bool IsStatic { + get { return attributes.GetAttributes ((ushort) MethodAttributes.Static); } + set { attributes = attributes.SetAttributes ((ushort) MethodAttributes.Static, value); } + } + + public bool IsFinal { + get { return attributes.GetAttributes ((ushort) MethodAttributes.Final); } + set { attributes = attributes.SetAttributes ((ushort) MethodAttributes.Final, value); } + } + + public bool IsVirtual { + get { return attributes.GetAttributes ((ushort) MethodAttributes.Virtual); } + set { attributes = attributes.SetAttributes ((ushort) MethodAttributes.Virtual, value); } + } + + public bool IsHideBySig { + get { return attributes.GetAttributes ((ushort) MethodAttributes.HideBySig); } + set { attributes = attributes.SetAttributes ((ushort) MethodAttributes.HideBySig, value); } + } + + public bool IsReuseSlot { + get { return attributes.GetMaskedAttributes ((ushort) MethodAttributes.VtableLayoutMask, (ushort) MethodAttributes.ReuseSlot); } + set { attributes = attributes.SetMaskedAttributes ((ushort) MethodAttributes.VtableLayoutMask, (ushort) MethodAttributes.ReuseSlot, value); } + } + + public bool IsNewSlot { + get { return attributes.GetMaskedAttributes ((ushort) MethodAttributes.VtableLayoutMask, (ushort) MethodAttributes.NewSlot); } + set { attributes = attributes.SetMaskedAttributes ((ushort) MethodAttributes.VtableLayoutMask, (ushort) MethodAttributes.NewSlot, value); } + } + + public bool IsCheckAccessOnOverride { + get { return attributes.GetAttributes ((ushort) MethodAttributes.CheckAccessOnOverride); } + set { attributes = attributes.SetAttributes ((ushort) MethodAttributes.CheckAccessOnOverride, value); } + } + + public bool IsAbstract { + get { return attributes.GetAttributes ((ushort) MethodAttributes.Abstract); } + set { attributes = attributes.SetAttributes ((ushort) MethodAttributes.Abstract, value); } + } + + public bool IsSpecialName { + get { return attributes.GetAttributes ((ushort) MethodAttributes.SpecialName); } + set { attributes = attributes.SetAttributes ((ushort) MethodAttributes.SpecialName, value); } + } + + public bool IsPInvokeImpl { + get { return attributes.GetAttributes ((ushort) MethodAttributes.PInvokeImpl); } + set { attributes = attributes.SetAttributes ((ushort) MethodAttributes.PInvokeImpl, value); } + } + + public bool IsUnmanagedExport { + get { return attributes.GetAttributes ((ushort) MethodAttributes.UnmanagedExport); } + set { attributes = attributes.SetAttributes ((ushort) MethodAttributes.UnmanagedExport, value); } + } + + public bool IsRuntimeSpecialName { + get { return attributes.GetAttributes ((ushort) MethodAttributes.RTSpecialName); } + set { attributes = attributes.SetAttributes ((ushort) MethodAttributes.RTSpecialName, value); } + } + + public bool HasSecurity { + get { return attributes.GetAttributes ((ushort) MethodAttributes.HasSecurity); } + set { attributes = attributes.SetAttributes ((ushort) MethodAttributes.HasSecurity, value); } + } + + #endregion + + #region MethodImplAttributes + + public bool IsIL { + get { return impl_attributes.GetMaskedAttributes ((ushort) MethodImplAttributes.CodeTypeMask, (ushort) MethodImplAttributes.IL); } + set { impl_attributes = impl_attributes.SetMaskedAttributes ((ushort) MethodImplAttributes.CodeTypeMask, (ushort) MethodImplAttributes.IL, value); } + } + + public bool IsNative { + get { return impl_attributes.GetMaskedAttributes ((ushort) MethodImplAttributes.CodeTypeMask, (ushort) MethodImplAttributes.Native); } + set { impl_attributes = impl_attributes.SetMaskedAttributes ((ushort) MethodImplAttributes.CodeTypeMask, (ushort) MethodImplAttributes.Native, value); } + } + + public bool IsRuntime { + get { return impl_attributes.GetMaskedAttributes ((ushort) MethodImplAttributes.CodeTypeMask, (ushort) MethodImplAttributes.Runtime); } + set { impl_attributes = impl_attributes.SetMaskedAttributes ((ushort) MethodImplAttributes.CodeTypeMask, (ushort) MethodImplAttributes.Runtime, value); } + } + + public bool IsUnmanaged { + get { return impl_attributes.GetMaskedAttributes ((ushort) MethodImplAttributes.ManagedMask, (ushort) MethodImplAttributes.Unmanaged); } + set { impl_attributes = impl_attributes.SetMaskedAttributes ((ushort) MethodImplAttributes.ManagedMask, (ushort) MethodImplAttributes.Unmanaged, value); } + } + + public bool IsManaged { + get { return impl_attributes.GetMaskedAttributes ((ushort) MethodImplAttributes.ManagedMask, (ushort) MethodImplAttributes.Managed); } + set { impl_attributes = impl_attributes.SetMaskedAttributes ((ushort) MethodImplAttributes.ManagedMask, (ushort) MethodImplAttributes.Managed, value); } + } + + public bool IsForwardRef { + get { return impl_attributes.GetAttributes ((ushort) MethodImplAttributes.ForwardRef); } + set { impl_attributes = impl_attributes.SetAttributes ((ushort) MethodImplAttributes.ForwardRef, value); } + } + + public bool IsPreserveSig { + get { return impl_attributes.GetAttributes ((ushort) MethodImplAttributes.PreserveSig); } + set { impl_attributes = impl_attributes.SetAttributes ((ushort) MethodImplAttributes.PreserveSig, value); } + } + + public bool IsInternalCall { + get { return impl_attributes.GetAttributes ((ushort) MethodImplAttributes.InternalCall); } + set { impl_attributes = impl_attributes.SetAttributes ((ushort) MethodImplAttributes.InternalCall, value); } + } + + public bool IsSynchronized { + get { return impl_attributes.GetAttributes ((ushort) MethodImplAttributes.Synchronized); } + set { impl_attributes = impl_attributes.SetAttributes ((ushort) MethodImplAttributes.Synchronized, value); } + } + + public bool NoInlining { + get { return impl_attributes.GetAttributes ((ushort) MethodImplAttributes.NoInlining); } + set { impl_attributes = impl_attributes.SetAttributes ((ushort) MethodImplAttributes.NoInlining, value); } + } + + public bool NoOptimization { + get { return impl_attributes.GetAttributes ((ushort) MethodImplAttributes.NoOptimization); } + set { impl_attributes = impl_attributes.SetAttributes ((ushort) MethodImplAttributes.NoOptimization, value); } + } + + #endregion + + #region MethodSemanticsAttributes + + public bool IsSetter { + get { return this.GetSemantics (MethodSemanticsAttributes.Setter); } + set { this.SetSemantics (MethodSemanticsAttributes.Setter, value); } + } + + public bool IsGetter { + get { return this.GetSemantics (MethodSemanticsAttributes.Getter); } + set { this.SetSemantics (MethodSemanticsAttributes.Getter, value); } + } + + public bool IsOther { + get { return this.GetSemantics (MethodSemanticsAttributes.Other); } + set { this.SetSemantics (MethodSemanticsAttributes.Other, value); } + } + + public bool IsAddOn { + get { return this.GetSemantics (MethodSemanticsAttributes.AddOn); } + set { this.SetSemantics (MethodSemanticsAttributes.AddOn, value); } + } + + public bool IsRemoveOn { + get { return this.GetSemantics (MethodSemanticsAttributes.RemoveOn); } + set { this.SetSemantics (MethodSemanticsAttributes.RemoveOn, value); } + } + + public bool IsFire { + get { return this.GetSemantics (MethodSemanticsAttributes.Fire); } + set { this.SetSemantics (MethodSemanticsAttributes.Fire, value); } + } + + #endregion + + public new TypeDefinition DeclaringType { + get { return (TypeDefinition) base.DeclaringType; } + set { base.DeclaringType = value; } + } + + public bool IsConstructor { + get { + return this.IsRuntimeSpecialName + && this.IsSpecialName + && (this.Name == ".cctor" || this.Name == ".ctor"); + } + } + + public override bool IsDefinition { + get { return true; } + } + + internal MethodDefinition () + { + this.token = new MetadataToken (TokenType.Method); + } + + public MethodDefinition (string name, MethodAttributes attributes, TypeReference returnType) + : base (name, returnType) + { + this.attributes = (ushort) attributes; + this.HasThis = !this.IsStatic; + this.token = new MetadataToken (TokenType.Method); + } + + public override MethodDefinition Resolve () + { + return this; + } + } + + static partial class Mixin { + + public static ParameterDefinition GetParameter (this MethodBody self, int index) + { + var method = self.method; + + if (method.HasThis) { + if (index == 0) + return self.ThisParameter; + + index--; + } + + var parameters = method.Parameters; + + if (index < 0 || index >= parameters.size) + return null; + + return parameters [index]; + } + + public static VariableDefinition GetVariable (this MethodBody self, int index) + { + var variables = self.Variables; + + if (index < 0 || index >= variables.size) + return null; + + return variables [index]; + } + + public static bool GetSemantics (this MethodDefinition self, MethodSemanticsAttributes semantics) + { + return (self.SemanticsAttributes & semantics) != 0; + } + + public static void SetSemantics (this MethodDefinition self, MethodSemanticsAttributes semantics, bool value) + { + if (value) + self.SemanticsAttributes |= semantics; + else + self.SemanticsAttributes &= ~semantics; + } + } +} diff --git a/Mono.Cecil/MethodImplAttributes.cs b/Mono.Cecil/MethodImplAttributes.cs new file mode 100644 index 000000000..8a2b422cc --- /dev/null +++ b/Mono.Cecil/MethodImplAttributes.cs @@ -0,0 +1,54 @@ +// +// MethodImplAttributes.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace Mono.Cecil { + + [Flags] + public enum MethodImplAttributes : ushort { + CodeTypeMask = 0x0003, + IL = 0x0000, // Method impl is CIL + Native = 0x0001, // Method impl is native + OPTIL = 0x0002, // Reserved: shall be zero in conforming implementations + Runtime = 0x0003, // Method impl is provided by the runtime + + ManagedMask = 0x0004, // Flags specifying whether the code is managed or unmanaged + Unmanaged = 0x0004, // Method impl is unmanaged, otherwise managed + Managed = 0x0000, // Method impl is managed + + // Implementation info and interop + ForwardRef = 0x0010, // Indicates method is defined; used primarily in merge scenarios + PreserveSig = 0x0080, // Reserved: conforming implementations may ignore + InternalCall = 0x1000, // Reserved: shall be zero in conforming implementations + Synchronized = 0x0020, // Method is single threaded through the body + NoOptimization = 0x0040, // Method is not optimized by the JIT. + NoInlining = 0x0008, // Method may not be inlined + MaxMethodImplVal = 0xffff // Range check value + } +} diff --git a/Mono.Cecil/MethodReference.cs b/Mono.Cecil/MethodReference.cs new file mode 100644 index 000000000..6a9dbe926 --- /dev/null +++ b/Mono.Cecil/MethodReference.cs @@ -0,0 +1,214 @@ +// +// MethodReference.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Text; + +using Mono.Collections.Generic; + +namespace Mono.Cecil { + + public class MethodReference : MemberReference, IMethodSignature, IGenericParameterProvider, IGenericContext { + + internal ParameterDefinitionCollection parameters; + MethodReturnType return_type; + + bool has_this; + bool explicit_this; + MethodCallingConvention calling_convention; + internal Collection generic_parameters; + + public virtual bool HasThis { + get { return has_this; } + set { has_this = value; } + } + + public virtual bool ExplicitThis { + get { return explicit_this; } + set { explicit_this = value; } + } + + public virtual MethodCallingConvention CallingConvention { + get { return calling_convention; } + set { calling_convention = value; } + } + + public virtual bool HasParameters { + get { return !parameters.IsNullOrEmpty (); } + } + + public virtual Collection Parameters { + get { + if (parameters == null) + parameters = new ParameterDefinitionCollection (this); + + return parameters; + } + } + + IGenericParameterProvider IGenericContext.Type { + get { + var declaring_type = this.DeclaringType; + var instance = declaring_type as GenericInstanceType; + if (instance != null) + return instance.ElementType; + + return declaring_type; + } + } + + IGenericParameterProvider IGenericContext.Method { + get { return this; } + } + + GenericParameterType IGenericParameterProvider.GenericParameterType { + get { return GenericParameterType.Method; } + } + + public virtual bool HasGenericParameters { + get { return !generic_parameters.IsNullOrEmpty (); } + } + + public virtual Collection GenericParameters { + get { + if (generic_parameters != null) + return generic_parameters; + + return generic_parameters = new Collection (); + } + } + + public TypeReference ReturnType { + get { + var return_type = MethodReturnType; + return return_type != null ? return_type.ReturnType : null; + } + set { + var return_type = MethodReturnType; + if (return_type != null) + return_type.ReturnType = value; + } + } + + public virtual MethodReturnType MethodReturnType { + get { return return_type; } + set { return_type = value; } + } + + public override string FullName { + get { + var builder = new StringBuilder (); + builder.Append (ReturnType.FullName) + .Append (" ") + .Append (MemberFullName ()); + this.MethodSignatureFullName (builder); + return builder.ToString (); + } + } + + public virtual bool IsGenericInstance { + get { return false; } + } + + internal override bool ContainsGenericParameter { + get { + if (this.ReturnType.ContainsGenericParameter || base.ContainsGenericParameter) + return true; + + var parameters = this.Parameters; + + for (int i = 0; i < parameters.Count; i++) + if (parameters [i].ParameterType.ContainsGenericParameter) + return true; + + return false; + } + } + + internal MethodReference () + { + this.return_type = new MethodReturnType (this); + this.token = new MetadataToken (TokenType.MemberRef); + } + + public MethodReference (string name, TypeReference returnType) + : base (name) + { + if (returnType == null) + throw new ArgumentNullException ("returnType"); + + this.return_type = new MethodReturnType (this); + this.return_type.ReturnType = returnType; + this.token = new MetadataToken (TokenType.MemberRef); + } + + public MethodReference (string name, TypeReference returnType, TypeReference declaringType) + : this (name, returnType) + { + if (declaringType == null) + throw new ArgumentNullException ("declaringType"); + + this.DeclaringType = declaringType; + } + + public virtual MethodReference GetElementMethod () + { + return this; + } + + public virtual MethodDefinition Resolve () + { + var module = this.Module; + if (module == null) + throw new NotSupportedException (); + + return module.Resolve (this); + } + } + + static partial class Mixin { + + public static bool IsVarArg (this IMethodSignature self) + { + return (self.CallingConvention & MethodCallingConvention.VarArg) != 0; + } + + public static int GetSentinelPosition (this IMethodSignature self) + { + if (!self.HasParameters) + return -1; + + var parameters = self.Parameters; + for (int i = 0; i < parameters.Count; i++) + if (parameters [i].ParameterType.IsSentinel) + return i; + + return -1; + } + } +} diff --git a/Mono.Cecil/MethodReturnType.cs b/Mono.Cecil/MethodReturnType.cs new file mode 100644 index 000000000..045b9a876 --- /dev/null +++ b/Mono.Cecil/MethodReturnType.cs @@ -0,0 +1,100 @@ +// +// MethodReturnType.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using Mono.Collections.Generic; + +namespace Mono.Cecil { + + public sealed class MethodReturnType : IConstantProvider, ICustomAttributeProvider, IMarshalInfoProvider { + + internal IMethodSignature method; + internal ParameterDefinition parameter; + TypeReference return_type; + + public IMethodSignature Method { + get { return method; } + } + + public TypeReference ReturnType { + get { return return_type; } + set { return_type = value; } + } + + internal ParameterDefinition Parameter { + get { return parameter ?? (parameter = new ParameterDefinition (return_type)); } + set { parameter = value; } + } + + public MetadataToken MetadataToken { + get { return Parameter.MetadataToken; } + set { Parameter.MetadataToken = value; } + } + + public bool HasCustomAttributes { + get { return parameter != null && parameter.HasCustomAttributes; } + } + + public Collection CustomAttributes { + get { return Parameter.CustomAttributes; } + } + + public bool HasDefault { + get { return parameter != null && parameter.HasDefault; } + set { Parameter.HasDefault = value; } + } + + public bool HasConstant { + get { return parameter != null && parameter.HasConstant; } + set { Parameter.HasConstant = value; } + } + + public object Constant { + get { return Parameter.Constant; } + set { Parameter.Constant = value; } + } + + public bool HasFieldMarshal { + get { return parameter != null && parameter.HasFieldMarshal; } + set { Parameter.HasFieldMarshal = value; } + } + + public bool HasMarshalInfo { + get { return parameter != null && parameter.HasMarshalInfo; } + } + + public MarshalInfo MarshalInfo { + get { return Parameter.MarshalInfo; } + set { Parameter.MarshalInfo = value; } + } + + public MethodReturnType (IMethodSignature method) + { + this.method = method; + } + } +} diff --git a/Mono.Cecil/MethodSemanticsAttributes.cs b/Mono.Cecil/MethodSemanticsAttributes.cs new file mode 100644 index 000000000..f44a3fa81 --- /dev/null +++ b/Mono.Cecil/MethodSemanticsAttributes.cs @@ -0,0 +1,43 @@ +// +// MethodSemanticsattributes.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace Mono.Cecil { + + [Flags] + public enum MethodSemanticsAttributes : ushort { + None = 0x0000, + Setter = 0x0001, // Setter for property + Getter = 0x0002, // Getter for property + Other = 0x0004, // Other method for property or event + AddOn = 0x0008, // AddOn method for event + RemoveOn = 0x0010, // RemoveOn method for event + Fire = 0x0020 // Fire method for event + } +} diff --git a/Mono.Cecil/MethodSpecification.cs b/Mono.Cecil/MethodSpecification.cs new file mode 100644 index 000000000..e907d6cc0 --- /dev/null +++ b/Mono.Cecil/MethodSpecification.cs @@ -0,0 +1,103 @@ +// +// MethodSpecification.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +using Mono.Collections.Generic; + +namespace Mono.Cecil { + + public abstract class MethodSpecification : MethodReference { + + readonly MethodReference method; + + public MethodReference ElementMethod { + get { return method; } + } + + public override string Name { + get { return method.Name; } + set { throw new InvalidOperationException (); } + } + + public override MethodCallingConvention CallingConvention { + get { return method.CallingConvention; } + set { throw new InvalidOperationException (); } + } + + public override bool HasThis { + get { return method.HasThis; } + set { throw new InvalidOperationException (); } + } + + public override bool ExplicitThis { + get { return method.ExplicitThis; } + set { throw new InvalidOperationException (); } + } + + public override MethodReturnType MethodReturnType { + get { return method.MethodReturnType; } + set { throw new InvalidOperationException (); } + } + + public override TypeReference DeclaringType { + get { return method.DeclaringType; } + set { throw new InvalidOperationException (); } + } + + public override ModuleDefinition Module { + get { return method.Module; } + } + + public override bool HasParameters { + get { return method.HasParameters; } + } + + public override Collection Parameters { + get { return method.Parameters; } + } + + internal override bool ContainsGenericParameter { + get { return method.ContainsGenericParameter; } + } + + internal MethodSpecification (MethodReference method) + { + if (method == null) + throw new ArgumentNullException ("method"); + + this.method = method; + this.token = new MetadataToken (TokenType.MethodSpec); + } + + public sealed override MethodReference GetElementMethod () + { + return method.GetElementMethod (); + } + } +} diff --git a/Mono.Cecil/Modifiers.cs b/Mono.Cecil/Modifiers.cs new file mode 100644 index 000000000..f7ff611ac --- /dev/null +++ b/Mono.Cecil/Modifiers.cs @@ -0,0 +1,137 @@ +// +// Modifiers.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +using MD = Mono.Cecil.Metadata; + +namespace Mono.Cecil { + + public interface IModifierType { + TypeReference ModifierType { get; } + TypeReference ElementType { get; } + } + + public sealed class OptionalModifierType : TypeSpecification, IModifierType { + + TypeReference modifier_type; + + public TypeReference ModifierType { + get { return modifier_type; } + set { modifier_type = value; } + } + + public override string Name { + get { return base.Name + Suffix; } + } + + public override string FullName { + get { return base.FullName + Suffix; } + } + + string Suffix { + get { return " modopt(" + modifier_type + ")"; } + } + + public override bool IsValueType { + get { return false; } + set { throw new InvalidOperationException (); } + } + + public override bool IsOptionalModifier { + get { return true; } + } + + internal override bool ContainsGenericParameter { + get { return modifier_type.ContainsGenericParameter || base.ContainsGenericParameter; } + } + + public OptionalModifierType (TypeReference modifierType, TypeReference type) + : base (type) + { + Mixin.CheckModifier (modifierType, type); + this.modifier_type = modifierType; + this.etype = MD.ElementType.CModOpt; + } + } + + public sealed class RequiredModifierType : TypeSpecification, IModifierType { + + TypeReference modifier_type; + + public TypeReference ModifierType { + get { return modifier_type; } + set { modifier_type = value; } + } + + public override string Name { + get { return base.Name + Suffix; } + } + + public override string FullName { + get { return base.FullName + Suffix; } + } + + string Suffix { + get { return " modreq(" + modifier_type + ")"; } + } + + public override bool IsValueType { + get { return false; } + set { throw new InvalidOperationException (); } + } + + public override bool IsRequiredModifier { + get { return true; } + } + + internal override bool ContainsGenericParameter { + get { return modifier_type.ContainsGenericParameter || base.ContainsGenericParameter; } + } + + public RequiredModifierType (TypeReference modifierType, TypeReference type) + : base (type) + { + Mixin.CheckModifier (modifierType, type); + this.modifier_type = modifierType; + this.etype = MD.ElementType.CModReqD; + } + + } + + static partial class Mixin { + + public static void CheckModifier (TypeReference modifierType, TypeReference type) + { + if (modifierType == null) + throw new ArgumentNullException ("modifierType"); + if (type == null) + throw new ArgumentNullException ("type"); + } + } +} diff --git a/Mono.Cecil/ModuleDefinition.cs b/Mono.Cecil/ModuleDefinition.cs new file mode 100644 index 000000000..7c793f5a2 --- /dev/null +++ b/Mono.Cecil/ModuleDefinition.cs @@ -0,0 +1,965 @@ +// +// ModuleDefinition.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Generic; +using System.IO; +using SR = System.Reflection; + +using Mono.Cecil.Cil; +using Mono.Cecil.Metadata; +using Mono.Cecil.PE; +using Mono.Collections.Generic; + +namespace Mono.Cecil { + + public enum ReadingMode { + Immediate = 1, + Deferred = 2, + } + + public sealed class ReaderParameters { + + ReadingMode reading_mode; + IAssemblyResolver assembly_resolver; + Stream symbol_stream; + ISymbolReaderProvider symbol_reader_provider; + bool read_symbols; + + public ReadingMode ReadingMode { + get { return reading_mode; } + set { reading_mode = value; } + } + + public IAssemblyResolver AssemblyResolver { + get { return assembly_resolver; } + set { assembly_resolver = value; } + } + + public Stream SymbolStream { + get { return symbol_stream; } + set { symbol_stream = value; } + } + + public ISymbolReaderProvider SymbolReaderProvider { + get { return symbol_reader_provider; } + set { symbol_reader_provider = value; } + } + + public bool ReadSymbols { + get { return read_symbols; } + set { read_symbols = value; } + } + + public ReaderParameters () + : this (ReadingMode.Deferred) + { + } + + public ReaderParameters (ReadingMode readingMode) + { + this.reading_mode = readingMode; + } + } + +#if !READ_ONLY + + public sealed class ModuleParameters { + + ModuleKind kind; + TargetRuntime runtime; + TargetArchitecture architecture; + IAssemblyResolver assembly_resolver; + + public ModuleKind Kind { + get { return kind; } + set { kind = value; } + } + + public TargetRuntime Runtime { + get { return runtime; } + set { runtime = value; } + } + + public TargetArchitecture Architecture { + get { return architecture; } + set { architecture = value; } + } + + public IAssemblyResolver AssemblyResolver { + get { return assembly_resolver; } + set { assembly_resolver = value; } + } + + public ModuleParameters () + { + this.kind = ModuleKind.Dll; + this.runtime = GetCurrentRuntime (); + this.architecture = TargetArchitecture.I386; + } + + static TargetRuntime GetCurrentRuntime () + { +#if !CF + return typeof (object).Assembly.ImageRuntimeVersion.ParseRuntime (); +#else + var corlib_version = typeof (object).Assembly.GetName ().Version; + switch (corlib_version.Major) { + case 1: + return corlib_version.Minor == 0 + ? TargetRuntime.Net_1_0 + : TargetRuntime.Net_1_1; + case 2: + return TargetRuntime.Net_2_0; + case 4: + return TargetRuntime.Net_4_0; + default: + throw new NotSupportedException (); + } +#endif + } + } + + public sealed class WriterParameters { + + Stream symbol_stream; + ISymbolWriterProvider symbol_writer_provider; + bool write_symbols; +#if !SILVERLIGHT && !CF + SR.StrongNameKeyPair key_pair; +#endif + public Stream SymbolStream { + get { return symbol_stream; } + set { symbol_stream = value; } + } + + public ISymbolWriterProvider SymbolWriterProvider { + get { return symbol_writer_provider; } + set { symbol_writer_provider = value; } + } + + public bool WriteSymbols { + get { return write_symbols; } + set { write_symbols = value; } + } +#if !SILVERLIGHT && !CF + public SR.StrongNameKeyPair StrongNameKeyPair { + get { return key_pair; } + set { key_pair = value; } + } +#endif + } + +#endif + + public sealed class ModuleDefinition : ModuleReference, ICustomAttributeProvider { + + internal Image Image; + internal MetadataSystem MetadataSystem; + internal ReadingMode ReadingMode; + internal ISymbolReaderProvider SymbolReaderProvider; + internal ISymbolReader SymbolReader; + + internal IAssemblyResolver assembly_resolver; + internal TypeSystem type_system; + + readonly MetadataReader reader; + readonly string fq_name; + + internal ModuleKind kind; + TargetRuntime runtime; + TargetArchitecture architecture; + ModuleAttributes attributes; + Guid mvid; + + internal AssemblyDefinition assembly; + MethodDefinition entry_point; + +#if !READ_ONLY + MetadataImporter importer; +#endif + Collection custom_attributes; + Collection references; + Collection modules; + Collection resources; + Collection exported_types; + TypeDefinitionCollection types; + + public bool IsMain { + get { return kind != ModuleKind.NetModule; } + } + + public ModuleKind Kind { + get { return kind; } + set { kind = value; } + } + + public TargetRuntime Runtime { + get { return runtime; } + set { runtime = value; } + } + + public TargetArchitecture Architecture { + get { return architecture; } + set { architecture = value; } + } + + public ModuleAttributes Attributes { + get { return attributes; } + set { attributes = value; } + } + + public string FullyQualifiedName { + get { return fq_name; } + } + + public Guid Mvid { + get { return mvid; } + set { mvid = value; } + } + + internal bool HasImage { + get { return Image != null; } + } + + public bool HasSymbols { + get { return SymbolReader != null; } + } + + public override MetadataScopeType MetadataScopeType { + get { return MetadataScopeType.ModuleDefinition; } + } + + public AssemblyDefinition Assembly { + get { return assembly; } + } + +#if !READ_ONLY + internal MetadataImporter MetadataImporter { + get { return importer ?? (importer = new MetadataImporter (this)); } + } +#endif + + public IAssemblyResolver AssemblyResolver { + get { return assembly_resolver; } + } + + public TypeSystem TypeSystem { + get { return type_system ?? (type_system = TypeSystem.CreateTypeSystem (this)); } + } + + public bool HasAssemblyReferences { + get { + if (references != null) + return references.Count > 0; + + return HasImage && Image.HasTable (Table.AssemblyRef); + } + } + + public Collection AssemblyReferences { + get { + if (references != null) + return references; + + if (HasImage) + return references = Read (this, (_, reader) => reader.ReadAssemblyReferences ()); + + return references = new Collection (); + } + } + + public bool HasModuleReferences { + get { + if (modules != null) + return modules.Count > 0; + + return HasImage && Image.HasTable (Table.ModuleRef); + } + } + + public Collection ModuleReferences { + get { + if (modules != null) + return modules; + + if (HasImage) + return modules = Read (this, (_, reader) => reader.ReadModuleReferences ()); + + return modules = new Collection (); + } + } + + public bool HasResources { + get { + if (resources != null) + return resources.Count > 0; + + if (HasImage) + return Image.HasTable (Table.ManifestResource) || Read (this, (_, reader) => reader.HasFileResource ()); + + return false; + } + } + + public Collection Resources { + get { + if (resources != null) + return resources; + + if (HasImage) + return resources = Read (this, (_, reader) => reader.ReadResources ()); + + return resources = new Collection (); + } + } + + public bool HasCustomAttributes { + get { + if (custom_attributes != null) + return custom_attributes.Count > 0; + + return this.GetHasCustomAttributes (this); + } + } + + public Collection CustomAttributes { + get { return custom_attributes ?? (custom_attributes = this.GetCustomAttributes (this)); } + } + + public bool HasTypes { + get { + if (types != null) + return types.Count > 0; + + return HasImage && Image.HasTable (Table.TypeDef); + } + } + + public Collection Types { + get { + if (types != null) + return types; + + if (HasImage) + return types = Read (this, (_, reader) => reader.ReadTypes ()); + + return types = new TypeDefinitionCollection (this); + } + } + + public bool HasExportedTypes { + get { + if (exported_types != null) + return exported_types.Count > 0; + + return HasImage && Image.HasTable (Table.ExportedType); + } + } + + public Collection ExportedTypes { + get { + if (exported_types != null) + return exported_types; + + if (HasImage) + return exported_types = Read (this, (_, reader) => reader.ReadExportedTypes ()); + + return exported_types = new Collection (); + } + } + + public MethodDefinition EntryPoint { + get { + if (entry_point != null) + return entry_point; + + if (HasImage) + return entry_point = Read (this, (_, reader) => reader.ReadEntryPoint ()); + + return entry_point = null; + } + set { entry_point = value; } + } + + internal ModuleDefinition () + { + this.MetadataSystem = new MetadataSystem (); + this.token = new MetadataToken (TokenType.Module, 1); + this.assembly_resolver = GlobalAssemblyResolver.Instance; + } + + internal ModuleDefinition (Image image) + : this () + { + this.Image = image; + this.kind = image.Kind; + this.runtime = image.Runtime; + this.architecture = image.Architecture; + this.attributes = image.Attributes; + this.fq_name = image.FileName; + + this.reader = new MetadataReader (this); + } + + public bool HasTypeReference (string fullName) + { + return HasTypeReference (string.Empty, fullName); + } + + public bool HasTypeReference (string scope, string fullName) + { + CheckFullName (fullName); + + if (!HasImage) + return false; + + return Read (this, (_, reader) => reader.GetTypeReference (scope, fullName) != null); + } + + public bool TryGetTypeReference (string fullName, out TypeReference type) + { + return TryGetTypeReference (string.Empty, fullName, out type); + } + + public bool TryGetTypeReference (string scope, string fullName, out TypeReference type) + { + CheckFullName (fullName); + + if (!HasImage) { + type = null; + return false; + } + + return (type = Read (this, (_, reader) => reader.GetTypeReference (scope, fullName))) != null; + } + + public IEnumerable GetTypeReferences () + { + if (!HasImage) + return Empty.Array; + + return Read (this, (_, reader) => reader.GetTypeReferences ()); + } + + public IEnumerable GetMemberReferences () + { + if (!HasImage) + return Empty.Array; + + return Read (this, (_, reader) => reader.GetMemberReferences ()); + } + + public TypeDefinition GetType (string fullName) + { + CheckFullName (fullName); + + var position = fullName.IndexOf ('/'); + if (position > 0) + return GetNestedType (fullName); + + return ((TypeDefinitionCollection) this.Types).GetType (fullName); + } + + public TypeDefinition GetType (string @namespace, string name) + { + Mixin.CheckName (name); + + return ((TypeDefinitionCollection) this.Types).GetType (@namespace ?? string.Empty, name); + } + + static void CheckFullName (string fullName) + { + if (fullName == null) + throw new ArgumentNullException ("fullName"); + if (fullName.Length == 0) + throw new ArgumentException (); + } + + TypeDefinition GetNestedType (string fullname) + { + var names = fullname.Split ('/'); + var type = GetType (names [0]); + + if (type == null) + return null; + + for (int i = 1; i < names.Length; i++) { + var nested_type = type.GetNestedType (names [i]); + if (nested_type == null) + return null; + + type = nested_type; + } + + return type; + } + + internal FieldDefinition Resolve (FieldReference field) + { + return MetadataResolver.Resolve (AssemblyResolver, field); + } + + internal MethodDefinition Resolve (MethodReference method) + { + return MetadataResolver.Resolve (AssemblyResolver, method); + } + + internal TypeDefinition Resolve (TypeReference type) + { + return MetadataResolver.Resolve (AssemblyResolver, type); + } + +#if !READ_ONLY + + static void CheckType (object type) + { + if (type == null) + throw new ArgumentNullException ("type"); + } + + static void CheckField (object field) + { + if (field == null) + throw new ArgumentNullException ("field"); + } + + static void CheckMethod (object method) + { + if (method == null) + throw new ArgumentNullException ("method"); + } + + static void CheckContext (IGenericParameterProvider context, ModuleDefinition module) + { + if (context == null) + return; + + if (context.Module != module) + throw new ArgumentException (); + } + +#if !CF + public TypeReference Import (Type type) + { + CheckType (type); + + return MetadataImporter.ImportType (type, null, ImportGenericKind.Definition); + } + + public TypeReference Import (Type type, TypeReference context) + { + return Import (type, (IGenericParameterProvider) context); + } + + public TypeReference Import (Type type, MethodReference context) + { + return Import (type, (IGenericParameterProvider) context); + } + + TypeReference Import (Type type, IGenericParameterProvider context) + { + CheckType (type); + CheckContext (context, this); + + return MetadataImporter.ImportType ( + type, + (IGenericContext) context, + context != null + ? ImportGenericKind.Open + : ImportGenericKind.Definition); + } + + public FieldReference Import (SR.FieldInfo field) + { + CheckField (field); + + return MetadataImporter.ImportField (field, null); + } + + public FieldReference Import (SR.FieldInfo field, TypeReference context) + { + return Import (field, (IGenericParameterProvider) context); + } + + public FieldReference Import (SR.FieldInfo field, MethodReference context) + { + return Import (field, (IGenericParameterProvider) context); + } + + FieldReference Import (SR.FieldInfo field, IGenericParameterProvider context) + { + CheckField (field); + CheckContext (context, this); + + return MetadataImporter.ImportField (field, (IGenericContext) context); + } + + public MethodReference Import (SR.MethodBase method) + { + CheckMethod (method); + + return MetadataImporter.ImportMethod (method, null, ImportGenericKind.Definition); + } + + public MethodReference Import (SR.MethodBase method, TypeReference context) + { + return Import (method, (IGenericParameterProvider) context); + } + + public MethodReference Import (SR.MethodBase method, MethodReference context) + { + return Import (method, (IGenericParameterProvider) context); + } + + MethodReference Import (SR.MethodBase method, IGenericParameterProvider context) + { + CheckMethod (method); + CheckContext (context, this); + + return MetadataImporter.ImportMethod (method, + (IGenericContext) context, + context != null + ? ImportGenericKind.Open + : ImportGenericKind.Definition); + } +#endif + + public TypeReference Import (TypeReference type) + { + CheckType (type); + + if (type.Module == this) + return type; + + return MetadataImporter.ImportType (type, null); + } + + public TypeReference Import (TypeReference type, TypeReference context) + { + return Import (type, (IGenericParameterProvider) context); + } + + public TypeReference Import (TypeReference type, MethodReference context) + { + return Import (type, (IGenericParameterProvider) context); + } + + TypeReference Import (TypeReference type, IGenericParameterProvider context) + { + CheckType (type); + + if (type.Module == this) + return type; + + CheckContext (context, this); + + return MetadataImporter.ImportType (type, (IGenericContext) context); + } + + public FieldReference Import (FieldReference field) + { + CheckField (field); + + if (field.Module == this) + return field; + + return MetadataImporter.ImportField (field, null); + } + + public FieldReference Import (FieldReference field, TypeReference context) + { + return Import (field, (IGenericParameterProvider) context); + } + + public FieldReference Import (FieldReference field, MethodReference context) + { + return Import (field, (IGenericParameterProvider) context); + } + + FieldReference Import (FieldReference field, IGenericParameterProvider context) + { + CheckField (field); + + if (field.Module == this) + return field; + + CheckContext (context, this); + + return MetadataImporter.ImportField (field, (IGenericContext) context); + } + + public MethodReference Import (MethodReference method) + { + CheckMethod (method); + + if (method.Module == this) + return method; + + return MetadataImporter.ImportMethod (method, null); + } + + public MethodReference Import (MethodReference method, TypeReference context) + { + return Import (method, (IGenericParameterProvider) context); + } + + public MethodReference Import (MethodReference method, MethodReference context) + { + return Import (method, (IGenericParameterProvider) context); + } + + MethodReference Import (MethodReference method, IGenericParameterProvider context) + { + CheckMethod (method); + + if (method.Module == this) + return method; + + CheckContext (context, this); + + return MetadataImporter.ImportMethod (method, (IGenericContext) context); + } + +#endif + + public IMetadataTokenProvider LookupToken (int token) + { + return LookupToken (new MetadataToken ((uint) token)); + } + + public IMetadataTokenProvider LookupToken (MetadataToken token) + { + return Read (this, (_, reader) => reader.LookupToken (token)); + } + + internal TRet Read (TItem item, Func read) + { + var position = reader.position; + var context = reader.context; + + var ret = read (item, reader); + + reader.position = position; + reader.context = context; + + return ret; + } + + void ProcessDebugHeader () + { + if (Image == null || Image.Debug.IsZero) + return; + + byte [] header; + var directory = Image.GetDebugHeader (out header); + + if (!SymbolReader.ProcessDebugHeader (directory, header)) + throw new InvalidOperationException (); + } + +#if !READ_ONLY + + public static ModuleDefinition CreateModule (string name, ModuleKind kind) + { + return CreateModule (name, new ModuleParameters { Kind = kind }); + } + + public static ModuleDefinition CreateModule (string name, ModuleParameters parameters) + { + Mixin.CheckName (name); + Mixin.CheckParameters (parameters); + + var module = new ModuleDefinition { + Name = name, + kind = parameters.Kind, + runtime = parameters.Runtime, + architecture = parameters.Architecture, + mvid = Guid.NewGuid (), + Attributes = ModuleAttributes.ILOnly, + }; + + if (parameters.AssemblyResolver != null) + module.assembly_resolver = parameters.AssemblyResolver; + + if (parameters.Kind != ModuleKind.NetModule) { + var assembly = new AssemblyDefinition (); + module.assembly = assembly; + module.assembly.Name = new AssemblyNameDefinition (name, new Version (0, 0)); + assembly.main_module = module; + } + + module.Types.Add (new TypeDefinition (string.Empty, "", TypeAttributes.NotPublic)); + + return module; + } + +#endif + + public void ReadSymbols () + { + if (string.IsNullOrEmpty (fq_name)) + throw new InvalidOperationException (); + + var provider = SymbolProvider.GetPlatformReaderProvider (); + + SymbolReader = provider.GetSymbolReader (this, fq_name); + + ProcessDebugHeader (); + } + + public void ReadSymbols (ISymbolReader reader) + { + if (reader == null) + throw new ArgumentNullException ("reader"); + + SymbolReader = reader; + + ProcessDebugHeader (); + } + + public static ModuleDefinition ReadModule (string fileName) + { + return ReadModule (fileName, new ReaderParameters (ReadingMode.Deferred)); + } + + public static ModuleDefinition ReadModule (Stream stream) + { + return ReadModule (stream, new ReaderParameters (ReadingMode.Deferred)); + } + + public static ModuleDefinition ReadModule (string fileName, ReaderParameters parameters) + { + using (var stream = GetFileStream (fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) { + return ReadModule (stream, parameters); + } + } + + static void CheckStream (object stream) + { + if (stream == null) + throw new ArgumentNullException ("stream"); + } + + public static ModuleDefinition ReadModule (Stream stream, ReaderParameters parameters) + { + CheckStream (stream); + if (!stream.CanRead || !stream.CanSeek) + throw new ArgumentException (); + Mixin.CheckParameters (parameters); + + return ModuleReader.CreateModuleFrom ( + ImageReader.ReadImageFrom (stream), + parameters); + } + + static Stream GetFileStream (string fileName, FileMode mode, FileAccess access, FileShare share) + { + if (fileName == null) + throw new ArgumentNullException ("fileName"); + if (fileName.Length == 0) + throw new ArgumentException (); + + return new FileStream (fileName, mode, access, share); + } + +#if !READ_ONLY + + public void Write (string fileName) + { + Write (fileName, new WriterParameters ()); + } + + public void Write (Stream stream) + { + Write (stream, new WriterParameters ()); + } + + public void Write (string fileName, WriterParameters parameters) + { + using (var stream = GetFileStream (fileName, FileMode.Create, FileAccess.ReadWrite, FileShare.None)) { + Write (stream, parameters); + } + } + + public void Write (Stream stream, WriterParameters parameters) + { + CheckStream (stream); + if (!stream.CanWrite || !stream.CanSeek) + throw new ArgumentException (); + Mixin.CheckParameters (parameters); + + ModuleWriter.WriteModuleTo (this, stream, parameters); + } + +#endif + + } + + static partial class Mixin { + + public static void CheckParameters (object parameters) + { + if (parameters == null) + throw new ArgumentNullException ("parameters"); + } + + public static bool HasImage (this ModuleDefinition self) + { + return self != null && self.HasImage; + } + + public static string GetFullyQualifiedName (this Stream self) + { +#if !SILVERLIGHT + var file_stream = self as FileStream; + if (file_stream == null) + return string.Empty; + + return Path.GetFullPath (file_stream.Name); +#else + return string.Empty; +#endif + } + + public static TargetRuntime ParseRuntime (this string self) + { + switch (self [1]) { + case '1': + return self [3] == '0' + ? TargetRuntime.Net_1_0 + : TargetRuntime.Net_1_1; + case '2': + return TargetRuntime.Net_2_0; + case '4': + default: + return TargetRuntime.Net_4_0; + } + } + } +} diff --git a/Mono.Cecil/ModuleKind.cs b/Mono.Cecil/ModuleKind.cs new file mode 100644 index 000000000..eb57890a9 --- /dev/null +++ b/Mono.Cecil/ModuleKind.cs @@ -0,0 +1,52 @@ +// +// ModuleKind.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace Mono.Cecil { + + public enum ModuleKind { + Dll, + Console, + Windows, + NetModule, + } + + public enum TargetArchitecture { + I386, + AMD64, + IA64, + } + + [Flags] + public enum ModuleAttributes { + ILOnly = 1, + Required32Bit = 2, + StrongNameSigned = 8, + } +} diff --git a/Mono.Cecil/ModuleReference.cs b/Mono.Cecil/ModuleReference.cs new file mode 100644 index 000000000..0b6e49aba --- /dev/null +++ b/Mono.Cecil/ModuleReference.cs @@ -0,0 +1,67 @@ +// +// ModuleReference.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace Mono.Cecil { + + public class ModuleReference : IMetadataScope { + + string name; + + internal MetadataToken token; + + public string Name { + get { return name; } + set { name = value; } + } + + public virtual MetadataScopeType MetadataScopeType { + get { return MetadataScopeType.ModuleReference; } + } + + public MetadataToken MetadataToken { + get { return token; } + set { token = value; } + } + + internal ModuleReference () + { + this.token = new MetadataToken (TokenType.ModuleRef); + } + + public ModuleReference (string name) + : this () + { + this.name = name; + } + + public override string ToString () + { + return name; + } + } +} diff --git a/Mono.Cecil/NativeType.cs b/Mono.Cecil/NativeType.cs new file mode 100644 index 000000000..afa107f07 --- /dev/null +++ b/Mono.Cecil/NativeType.cs @@ -0,0 +1,73 @@ +// +// NativeType.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace Mono.Cecil { + + public enum NativeType { + None = 0x66, + + Boolean = 0x02, + I1 = 0x03, + U1 = 0x04, + I2 = 0x05, + U2 = 0x06, + I4 = 0x07, + U4 = 0x08, + I8 = 0x09, + U8 = 0x0a, + R4 = 0x0b, + R8 = 0x0c, + LPStr = 0x14, + Int = 0x1f, + UInt = 0x20, + Func = 0x26, + Array = 0x2a, + + // Msft specific + Currency = 0x0f, + BStr = 0x13, + LPWStr = 0x15, + LPTStr = 0x16, + FixedSysString = 0x17, + IUnknown = 0x19, + IDispatch = 0x1a, + Struct = 0x1b, + IntF = 0x1c, + SafeArray = 0x1d, + FixedArray = 0x1e, + ByValStr = 0x22, + ANSIBStr = 0x23, + TBStr = 0x24, + VariantBool = 0x25, + ASAny = 0x28, + LPStruct = 0x2b, + CustomMarshaler = 0x2c, + Error = 0x2d, + Max = 0x50 + } +} diff --git a/Mono.Cecil/PInvokeAttributes.cs b/Mono.Cecil/PInvokeAttributes.cs new file mode 100644 index 000000000..fc9469253 --- /dev/null +++ b/Mono.Cecil/PInvokeAttributes.cs @@ -0,0 +1,62 @@ +// +// PInvokeAttributes.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace Mono.Cecil { + + [Flags] + public enum PInvokeAttributes : ushort { + NoMangle = 0x0001, // PInvoke is to use the member name as specified + + // Character set + CharSetMask = 0x0006, + CharSetNotSpec = 0x0000, + CharSetAnsi = 0x0002, + CharSetUnicode = 0x0004, + CharSetAuto = 0x0006, + + SupportsLastError = 0x0040, // Information about target function. Not relevant for fields + + // Calling convetion + CallConvMask = 0x0700, + CallConvWinapi = 0x0100, + CallConvCdecl = 0x0200, + CallConvStdCall = 0x0300, + CallConvThiscall = 0x0400, + CallConvFastcall = 0x0500, + + BestFitMask = 0x0030, + BestFitEnabled = 0x0010, + BestFidDisabled = 0x0020, + + ThrowOnUnmappableCharMask = 0x3000, + ThrowOnUnmappableCharEnabled = 0x1000, + ThrowOnUnmappableCharDisabled = 0x2000, + } +} diff --git a/Mono.Cecil/PInvokeInfo.cs b/Mono.Cecil/PInvokeInfo.cs new file mode 100644 index 000000000..53aae2c38 --- /dev/null +++ b/Mono.Cecil/PInvokeInfo.cs @@ -0,0 +1,138 @@ +// +// PInvokeInfo.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace Mono.Cecil { + + public sealed class PInvokeInfo { + + ushort attributes; + string entry_point; + ModuleReference module; + + public PInvokeAttributes Attributes { + get { return (PInvokeAttributes) attributes; } + set { attributes = (ushort) value; } + } + + public string EntryPoint { + get { return entry_point; } + set { entry_point = value; } + } + + public ModuleReference Module { + get { return module; } + set { module = value; } + } + + #region PInvokeAttributes + + public bool IsNoMangle { + get { return attributes.GetAttributes ((ushort) PInvokeAttributes.NoMangle); } + set { attributes = attributes.SetAttributes ((ushort) PInvokeAttributes.NoMangle, value); } + } + + public bool IsCharSetNotSpec { + get { return attributes.GetMaskedAttributes((ushort) PInvokeAttributes.CharSetMask, (ushort) PInvokeAttributes.CharSetNotSpec); } + set { attributes = attributes.SetMaskedAttributes ((ushort) PInvokeAttributes.CharSetMask, (ushort) PInvokeAttributes.CharSetNotSpec, value); } + } + + public bool IsCharSetAnsi { + get { return attributes.GetMaskedAttributes ((ushort) PInvokeAttributes.CharSetMask, (ushort) PInvokeAttributes.CharSetAnsi); } + set { attributes = attributes.SetMaskedAttributes ((ushort) PInvokeAttributes.CharSetMask, (ushort) PInvokeAttributes.CharSetAnsi, value); } + } + + public bool IsCharSetUnicode { + get { return attributes.GetMaskedAttributes ((ushort) PInvokeAttributes.CharSetMask, (ushort) PInvokeAttributes.CharSetUnicode); } + set { attributes = attributes.SetMaskedAttributes ((ushort) PInvokeAttributes.CharSetMask, (ushort) PInvokeAttributes.CharSetUnicode, value); } + } + + public bool IsCharSetAuto { + get { return attributes.GetMaskedAttributes ((ushort) PInvokeAttributes.CharSetMask, (ushort) PInvokeAttributes.CharSetAuto); } + set { attributes = attributes.SetMaskedAttributes ((ushort) PInvokeAttributes.CharSetMask, (ushort) PInvokeAttributes.CharSetAuto, value); } + } + + public bool SupportsLastError { + get { return attributes.GetAttributes ((ushort) PInvokeAttributes.SupportsLastError); } + set { attributes = attributes.SetAttributes ((ushort) PInvokeAttributes.SupportsLastError, value); } + } + + public bool IsCallConvWinapi { + get { return attributes.GetMaskedAttributes((ushort) PInvokeAttributes.CallConvMask, (ushort) PInvokeAttributes.CallConvWinapi); } + set { attributes = attributes.SetMaskedAttributes ((ushort) PInvokeAttributes.CallConvMask, (ushort) PInvokeAttributes.CallConvWinapi, value); } + } + + public bool IsCallConvCdecl { + get { return attributes.GetMaskedAttributes ((ushort) PInvokeAttributes.CallConvMask, (ushort) PInvokeAttributes.CallConvCdecl); } + set { attributes = attributes.SetMaskedAttributes ((ushort) PInvokeAttributes.CallConvMask, (ushort) PInvokeAttributes.CallConvCdecl, value); } + } + + public bool IsCallConvStdCall { + get { return attributes.GetMaskedAttributes ((ushort) PInvokeAttributes.CallConvMask, (ushort) PInvokeAttributes.CallConvStdCall); } + set { attributes = attributes.SetMaskedAttributes ((ushort) PInvokeAttributes.CallConvMask, (ushort) PInvokeAttributes.CallConvStdCall, value); } + } + + public bool IsCallConvThiscall { + get { return attributes.GetMaskedAttributes ((ushort) PInvokeAttributes.CallConvMask, (ushort) PInvokeAttributes.CallConvThiscall); } + set { attributes = attributes.SetMaskedAttributes ((ushort) PInvokeAttributes.CallConvMask, (ushort) PInvokeAttributes.CallConvThiscall, value); } + } + + public bool IsCallConvFastcall { + get { return attributes.GetMaskedAttributes ((ushort) PInvokeAttributes.CallConvMask, (ushort) PInvokeAttributes.CallConvFastcall); } + set { attributes = attributes.SetMaskedAttributes ((ushort) PInvokeAttributes.CallConvMask, (ushort) PInvokeAttributes.CallConvFastcall, value); } + } + + public bool IsBestFistEnabled { + get { return attributes.GetMaskedAttributes ((ushort) PInvokeAttributes.BestFitMask, (ushort) PInvokeAttributes.BestFitEnabled); } + set { attributes = attributes.SetMaskedAttributes ((ushort) PInvokeAttributes.BestFitMask, (ushort) PInvokeAttributes.BestFitEnabled, value); } + } + + public bool IsBestFistDisabled { + get { return attributes.GetMaskedAttributes ((ushort) PInvokeAttributes.BestFitMask, (ushort) PInvokeAttributes.BestFidDisabled); } + set { attributes = attributes.SetMaskedAttributes ((ushort) PInvokeAttributes.BestFitMask, (ushort) PInvokeAttributes.BestFidDisabled, value); } + } + + public bool IsThrowOnUnmappableCharEnabled { + get { return attributes.GetMaskedAttributes ((ushort) PInvokeAttributes.ThrowOnUnmappableCharMask, (ushort) PInvokeAttributes.ThrowOnUnmappableCharEnabled); } + set { attributes = attributes.SetMaskedAttributes ((ushort) PInvokeAttributes.ThrowOnUnmappableCharMask, (ushort) PInvokeAttributes.ThrowOnUnmappableCharEnabled, value); } + } + + public bool IsThrowOnUnmappableCharDisabled { + get { return attributes.GetMaskedAttributes ((ushort) PInvokeAttributes.ThrowOnUnmappableCharMask, (ushort) PInvokeAttributes.ThrowOnUnmappableCharDisabled); } + set { attributes = attributes.SetMaskedAttributes ((ushort) PInvokeAttributes.ThrowOnUnmappableCharMask, (ushort) PInvokeAttributes.ThrowOnUnmappableCharDisabled, value); } + } + + #endregion + + public PInvokeInfo (PInvokeAttributes attributes, string entryPoint, ModuleReference module) + { + this.attributes = (ushort) attributes; + this.entry_point = entryPoint; + this.module = module; + } + } +} diff --git a/Mono.Cecil/ParameterAttributes.cs b/Mono.Cecil/ParameterAttributes.cs new file mode 100644 index 000000000..8c12b5481 --- /dev/null +++ b/Mono.Cecil/ParameterAttributes.cs @@ -0,0 +1,45 @@ +// +// ParameterAttributes.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace Mono.Cecil { + + [Flags] + public enum ParameterAttributes : ushort { + None = 0x0000, + In = 0x0001, // Param is [In] + Out = 0x0002, // Param is [Out] + Lcid = 0x0004, + Retval = 0x0008, + Optional = 0x0010, // Param is optional + HasDefault = 0x1000, // Param has default value + HasFieldMarshal = 0x2000, // Param has field marshal + Unused = 0xcfe0 // Reserved: shall be zero in a conforming implementation + } +} diff --git a/Mono.Cecil/ParameterDefinition.cs b/Mono.Cecil/ParameterDefinition.cs new file mode 100644 index 000000000..059f257fc --- /dev/null +++ b/Mono.Cecil/ParameterDefinition.cs @@ -0,0 +1,157 @@ +// +// ParameterDefinition.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using Mono.Collections.Generic; + +namespace Mono.Cecil { + + public sealed class ParameterDefinition : ParameterReference, ICustomAttributeProvider, IConstantProvider, IMarshalInfoProvider { + + ushort attributes; + + internal IMethodSignature method; + + object constant = Mixin.NotResolved; + Collection custom_attributes; + MarshalInfo marshal_info; + + public ParameterAttributes Attributes { + get { return (ParameterAttributes) attributes; } + set { attributes = (ushort) value; } + } + + public IMethodSignature Method { + get { return method; } + } + + public bool HasConstant { + get { + ResolveConstant (); + + return constant != Mixin.NoValue; + } + set { if (!value) constant = Mixin.NoValue; } + } + + public object Constant { + get { return HasConstant ? constant : null; } + set { constant = value; } + } + + void ResolveConstant () + { + if (constant != Mixin.NotResolved) + return; + + this.ResolveConstant (ref constant, parameter_type.Module); + } + + public bool HasCustomAttributes { + get { + if (custom_attributes != null) + return custom_attributes.Count > 0; + + return this.GetHasCustomAttributes (parameter_type.Module); + } + } + + public Collection CustomAttributes { + get { return custom_attributes ?? (custom_attributes = this.GetCustomAttributes (parameter_type.Module)); } + } + + public bool HasMarshalInfo { + get { + if (marshal_info != null) + return true; + + return this.GetHasMarshalInfo (parameter_type.Module); + } + } + + public MarshalInfo MarshalInfo { + get { return marshal_info ?? (marshal_info = this.GetMarshalInfo (parameter_type.Module)); } + set { marshal_info = value; } + } + + #region ParameterAttributes + + public bool IsIn { + get { return attributes.GetAttributes ((ushort) ParameterAttributes.In); } + set { attributes = attributes.SetAttributes ((ushort) ParameterAttributes.In, value); } + } + + public bool IsOut { + get { return attributes.GetAttributes ((ushort) ParameterAttributes.Out); } + set { attributes = attributes.SetAttributes ((ushort) ParameterAttributes.Out, value); } + } + + public bool IsLcid { + get { return attributes.GetAttributes ((ushort) ParameterAttributes.Lcid); } + set { attributes = attributes.SetAttributes ((ushort) ParameterAttributes.Lcid, value); } + } + + public bool IsReturnValue { + get { return attributes.GetAttributes ((ushort) ParameterAttributes.Retval); } + set { attributes = attributes.SetAttributes ((ushort) ParameterAttributes.Retval, value); } + } + + public bool IsOptional { + get { return attributes.GetAttributes ((ushort) ParameterAttributes.Optional); } + set { attributes = attributes.SetAttributes ((ushort) ParameterAttributes.Optional, value); } + } + + public bool HasDefault { + get { return attributes.GetAttributes ((ushort) ParameterAttributes.HasDefault); } + set { attributes = attributes.SetAttributes ((ushort) ParameterAttributes.HasDefault, value); } + } + + public bool HasFieldMarshal { + get { return attributes.GetAttributes ((ushort) ParameterAttributes.HasFieldMarshal); } + set { attributes = attributes.SetAttributes ((ushort) ParameterAttributes.HasFieldMarshal, value); } + } + + #endregion + + public ParameterDefinition (TypeReference parameterType) + : this (string.Empty, ParameterAttributes.None, parameterType) + { + } + + public ParameterDefinition (string name, ParameterAttributes attributes, TypeReference parameterType) + : base (name, parameterType) + { + this.attributes = (ushort) attributes; + this.token = new MetadataToken (TokenType.Param); + } + + public override ParameterDefinition Resolve () + { + return this; + } + } +} diff --git a/Mono.Cecil/ParameterDefinitionCollection.cs b/Mono.Cecil/ParameterDefinitionCollection.cs new file mode 100644 index 000000000..86538bb9a --- /dev/null +++ b/Mono.Cecil/ParameterDefinitionCollection.cs @@ -0,0 +1,80 @@ +// +// ParameterDefinitionCollection.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +using Mono.Collections.Generic; + +namespace Mono.Cecil { + + sealed class ParameterDefinitionCollection : Collection { + + readonly IMethodSignature method; + + internal ParameterDefinitionCollection (IMethodSignature method) + { + this.method = method; + } + + internal ParameterDefinitionCollection (IMethodSignature method, int capacity) + : base (capacity) + { + this.method = method; + } + + protected override void OnAdd (ParameterDefinition item, int index) + { + item.method = method; + item.index = index; + } + + protected override void OnInsert (ParameterDefinition item, int index) + { + item.method = method; + item.index = index; + + for (int i = index; i < size; i++) + items [i].index = i + 1; + } + + protected override void OnSet (ParameterDefinition item, int index) + { + item.method = method; + item.index = index; + } + + protected override void OnRemove (ParameterDefinition item, int index) + { + item.method = null; + item.index = -1; + + for (int i = index + 1; i < size; i++) + items [i].index = i - 1; + } + } +} diff --git a/Mono.Cecil/ParameterReference.cs b/Mono.Cecil/ParameterReference.cs new file mode 100644 index 000000000..cfe648f2e --- /dev/null +++ b/Mono.Cecil/ParameterReference.cs @@ -0,0 +1,75 @@ +// +// ParameterReference.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace Mono.Cecil { + + public abstract class ParameterReference : IMetadataTokenProvider { + + string name; + internal int index = -1; + protected TypeReference parameter_type; + internal MetadataToken token; + + public string Name { + get { return name; } + set { name = value; } + } + + public int Index { + get { return index; } + } + + public TypeReference ParameterType { + get { return parameter_type; } + set { parameter_type = value; } + } + + public MetadataToken MetadataToken { + get { return token; } + set { token = value; } + } + + internal ParameterReference (string name, TypeReference parameterType) + { + if (parameterType == null) + throw new ArgumentNullException ("parameterType"); + + this.name = name ?? string.Empty; + this.parameter_type = parameterType; + } + + public override string ToString () + { + return name; + } + + public abstract ParameterDefinition Resolve (); + } +} diff --git a/Mono.Cecil/PinnedType.cs b/Mono.Cecil/PinnedType.cs new file mode 100644 index 000000000..d5e7a80c0 --- /dev/null +++ b/Mono.Cecil/PinnedType.cs @@ -0,0 +1,53 @@ +// +// PinnedType.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +using MD = Mono.Cecil.Metadata; + +namespace Mono.Cecil { + + public sealed class PinnedType : TypeSpecification { + + public override bool IsValueType { + get { return false; } + set { throw new InvalidOperationException (); } + } + + public override bool IsPinned { + get { return true; } + } + + public PinnedType (TypeReference type) + : base (type) + { + Mixin.CheckType (type); + this.etype = MD.ElementType.Pinned; + } + } +} diff --git a/Mono.Cecil/PointerType.cs b/Mono.Cecil/PointerType.cs new file mode 100644 index 000000000..54ab77519 --- /dev/null +++ b/Mono.Cecil/PointerType.cs @@ -0,0 +1,61 @@ +// +// PointerType.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +using MD = Mono.Cecil.Metadata; + +namespace Mono.Cecil { + + public sealed class PointerType : TypeSpecification { + + public override string Name { + get { return base.Name + "*"; } + } + + public override string FullName { + get { return base.FullName + "*"; } + } + + public override bool IsValueType { + get { return false; } + set { throw new InvalidOperationException (); } + } + + public override bool IsPointer { + get { return true; } + } + + public PointerType (TypeReference type) + : base (type) + { + Mixin.CheckType (type); + this.etype = MD.ElementType.Ptr; + } + } +} diff --git a/Mono.Cecil/PropertyAttributes.cs b/Mono.Cecil/PropertyAttributes.cs new file mode 100644 index 000000000..ad6fd9e8f --- /dev/null +++ b/Mono.Cecil/PropertyAttributes.cs @@ -0,0 +1,41 @@ +// +// PropertyAttributes.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace Mono.Cecil { + + [Flags] + public enum PropertyAttributes : ushort { + None = 0x0000, + SpecialName = 0x0200, // Property is special + RTSpecialName = 0x0400, // Runtime(metadata internal APIs) should check name encoding + HasDefault = 0x1000, // Property has default + Unused = 0xe9ff // Reserved: shall be zero in a conforming implementation + } +} diff --git a/Mono.Cecil/PropertyDefinition.cs b/Mono.Cecil/PropertyDefinition.cs new file mode 100644 index 000000000..c10814f5d --- /dev/null +++ b/Mono.Cecil/PropertyDefinition.cs @@ -0,0 +1,263 @@ +// +// PropertyDefinition.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System.Text; + +using Mono.Collections.Generic; + +namespace Mono.Cecil { + + public sealed class PropertyDefinition : PropertyReference, IMemberDefinition, IConstantProvider { + + bool? has_this; + ushort attributes; + + Collection custom_attributes; + + internal MethodDefinition get_method; + internal MethodDefinition set_method; + internal Collection other_methods; + + object constant = Mixin.NotResolved; + + public PropertyAttributes Attributes { + get { return (PropertyAttributes) attributes; } + set { attributes = (ushort) value; } + } + + public bool HasThis { + get { + if (has_this.HasValue) + return has_this.Value; + + if (GetMethod != null) + return get_method.HasThis; + + if (SetMethod != null) + return set_method.HasThis; + + return false; + } + set { has_this = value; } + } + + public bool HasCustomAttributes { + get { + if (custom_attributes != null) + return custom_attributes.Count > 0; + + return this.GetHasCustomAttributes (Module); + } + } + + public Collection CustomAttributes { + get { return custom_attributes ?? (custom_attributes = this.GetCustomAttributes (Module)); } + } + + public MethodDefinition GetMethod { + get { + if (get_method != null) + return get_method; + + InitializeMethods (); + return get_method; + } + set { get_method = value; } + } + + public MethodDefinition SetMethod { + get { + if (set_method != null) + return set_method; + + InitializeMethods (); + return set_method; + } + set { set_method = value; } + } + + public bool HasOtherMethods { + get { + if (other_methods != null) + return other_methods.Count > 0; + + InitializeMethods (); + return !other_methods.IsNullOrEmpty (); + } + } + + public Collection OtherMethods { + get { + if (other_methods != null) + return other_methods; + + InitializeMethods (); + + if (other_methods != null) + return other_methods; + + return other_methods = new Collection (); + } + } + + public bool HasParameters { + get { + if (get_method != null) + return get_method.HasParameters; + + if (set_method != null) + return set_method.HasParameters && set_method.Parameters.Count > 1; + + return false; + } + } + + public override Collection Parameters { + get { + InitializeMethods (); + + if (get_method != null) + return MirrorParameters (get_method, 0); + + if (set_method != null) + return MirrorParameters (set_method, 1); + + return new Collection (); + } + } + + static Collection MirrorParameters (MethodDefinition method, int bound) + { + var parameters = new Collection (); + if (!method.HasParameters) + return parameters; + + var original_parameters = method.Parameters; + var end = original_parameters.Count - bound; + + for (int i = 0; i < end; i++) + parameters.Add (original_parameters [i]); + + return parameters; + } + + public bool HasConstant { + get { + ResolveConstant (); + + return constant != Mixin.NoValue; + } + set { if (!value) constant = Mixin.NoValue; } + } + + public object Constant { + get { return HasConstant ? constant : null; } + set { constant = value; } + } + + void ResolveConstant () + { + if (constant != Mixin.NotResolved) + return; + + this.ResolveConstant (ref constant, Module); + } + + #region PropertyAttributes + + public bool IsSpecialName { + get { return attributes.GetAttributes ((ushort) PropertyAttributes.SpecialName); } + set { attributes = attributes.SetAttributes ((ushort) PropertyAttributes.SpecialName, value); } + } + + public bool IsRuntimeSpecialName { + get { return attributes.GetAttributes ((ushort) PropertyAttributes.RTSpecialName); } + set { attributes = attributes.SetAttributes ((ushort) PropertyAttributes.RTSpecialName, value); } + } + + public bool HasDefault { + get { return attributes.GetAttributes ((ushort) PropertyAttributes.HasDefault); } + set { attributes = attributes.SetAttributes ((ushort) PropertyAttributes.HasDefault, value); } + } + + #endregion + + public new TypeDefinition DeclaringType { + get { return (TypeDefinition) base.DeclaringType; } + set { base.DeclaringType = value; } + } + + public override bool IsDefinition { + get { return true; } + } + + public override string FullName { + get { + var builder = new StringBuilder (); + builder.Append (PropertyType.ToString ()); + builder.Append (' '); + builder.Append (MemberFullName ()); + builder.Append ('('); + if (HasParameters) { + var parameters = Parameters; + for (int i = 0; i < parameters.Count; i++) { + if (i > 0) + builder.Append (','); + builder.Append (parameters [i].ParameterType.FullName); + } + } + builder.Append (')'); + return builder.ToString (); + } + } + + public PropertyDefinition (string name, PropertyAttributes attributes, TypeReference propertyType) + : base (name, propertyType) + { + this.attributes = (ushort) attributes; + this.token = new MetadataToken (TokenType.Property); + } + + void InitializeMethods () + { + if (get_method != null || set_method != null) + return; + + var module = this.Module; + if (!module.HasImage ()) + return; + + module.Read (this, (property, reader) => reader.ReadMethods (property)); + } + + public override PropertyDefinition Resolve () + { + return this; + } + } +} diff --git a/Mono.Cecil/PropertyReference.cs b/Mono.Cecil/PropertyReference.cs new file mode 100644 index 000000000..d9a2c19ef --- /dev/null +++ b/Mono.Cecil/PropertyReference.cs @@ -0,0 +1,59 @@ +// +// PropertyReference.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +using Mono.Collections.Generic; + +namespace Mono.Cecil { + + public abstract class PropertyReference : MemberReference { + + TypeReference property_type; + + public TypeReference PropertyType { + get { return property_type; } + set { property_type = value; } + } + + public abstract Collection Parameters { + get; + } + + internal PropertyReference (string name, TypeReference propertyType) + : base (name) + { + if (propertyType == null) + throw new ArgumentNullException ("propertyType"); + + property_type = propertyType; + } + + public abstract PropertyDefinition Resolve (); + } +} diff --git a/Mono.Cecil/ReferenceType.cs b/Mono.Cecil/ReferenceType.cs new file mode 100644 index 000000000..3a6b326d4 --- /dev/null +++ b/Mono.Cecil/ReferenceType.cs @@ -0,0 +1,61 @@ +// +// ByReferenceType.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +using MD = Mono.Cecil.Metadata; + +namespace Mono.Cecil { + + public sealed class ByReferenceType : TypeSpecification { + + public override string Name { + get { return base.Name + "&"; } + } + + public override string FullName { + get { return base.FullName + "&"; } + } + + public override bool IsValueType { + get { return false; } + set { throw new InvalidOperationException (); } + } + + public override bool IsByReference { + get { return true; } + } + + public ByReferenceType (TypeReference type) + : base (type) + { + Mixin.CheckType (type); + this.etype = MD.ElementType.ByRef; + } + } +} diff --git a/Mono.Cecil/Resource.cs b/Mono.Cecil/Resource.cs new file mode 100644 index 000000000..0432ae789 --- /dev/null +++ b/Mono.Cecil/Resource.cs @@ -0,0 +1,76 @@ +// +// ResourceType.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace Mono.Cecil { + + public enum ResourceType { + Linked, + Embedded, + AssemblyLinked, + } + + public abstract class Resource { + + string name; + uint attributes; + + public string Name { + get { return name; } + set { name = value; } + } + + public ManifestResourceAttributes Attributes { + get { return (ManifestResourceAttributes) attributes; } + set { attributes = (uint) value; } + } + + public abstract ResourceType ResourceType { + get; + } + + #region ManifestResourceAttributes + + public bool IsPublic { + get { return attributes.GetMaskedAttributes ((uint) ManifestResourceAttributes.VisibilityMask, (uint) ManifestResourceAttributes.Public); } + set { attributes = attributes.SetMaskedAttributes ((uint) ManifestResourceAttributes.VisibilityMask, (uint) ManifestResourceAttributes.Public, value); } + } + + public bool IsPrivate { + get { return attributes.GetMaskedAttributes ((uint) ManifestResourceAttributes.VisibilityMask, (uint) ManifestResourceAttributes.Private); } + set { attributes = attributes.SetMaskedAttributes ((uint) ManifestResourceAttributes.VisibilityMask, (uint) ManifestResourceAttributes.Private, value); } + } + + #endregion + + internal Resource (string name, ManifestResourceAttributes attributes) + { + this.name = name; + this.attributes = (uint) attributes; + } + } +} diff --git a/Mono.Cecil/SecurityDeclaration.cs b/Mono.Cecil/SecurityDeclaration.cs new file mode 100644 index 000000000..4e57adae3 --- /dev/null +++ b/Mono.Cecil/SecurityDeclaration.cs @@ -0,0 +1,182 @@ +// +// SecurityDeclaration.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +using Mono.Collections.Generic; + +namespace Mono.Cecil { + + public enum SecurityAction : ushort { + Request = 1, + Demand = 2, + Assert = 3, + Deny = 4, + PermitOnly = 5, + LinkDemand = 6, + InheritDemand = 7, + RequestMinimum = 8, + RequestOptional = 9, + RequestRefuse = 10, + PreJitGrant = 11, + PreJitDeny = 12, + NonCasDemand = 13, + NonCasLinkDemand = 14, + NonCasInheritance = 15 + } + + public interface ISecurityDeclarationProvider : IMetadataTokenProvider { + + bool HasSecurityDeclarations { get; } + Collection SecurityDeclarations { get; } + } + + public sealed class SecurityAttribute : ICustomAttribute { + + TypeReference attribute_type; + + internal Collection fields; + internal Collection properties; + + public TypeReference AttributeType { + get { return attribute_type; } + set { attribute_type = value; } + } + + public bool HasFields { + get { return !fields.IsNullOrEmpty (); } + } + + public Collection Fields { + get { return fields ?? (fields = new Collection ()); } + } + + public bool HasProperties { + get { return !properties.IsNullOrEmpty (); } + } + + public Collection Properties { + get { return properties ?? (properties = new Collection ()); } + } + + public SecurityAttribute (TypeReference attributeType) + { + this.attribute_type = attributeType; + } + } + + public sealed class SecurityDeclaration { + + readonly internal uint signature; + readonly ModuleDefinition module; + + internal bool resolved; + SecurityAction action; + internal Collection security_attributes; + + public SecurityAction Action { + get { return action; } + set { action = value; } + } + + public bool HasSecurityAttributes { + get { + Resolve (); + + return !security_attributes.IsNullOrEmpty (); + } + } + + public Collection SecurityAttributes { + get { + Resolve (); + + return security_attributes ?? (security_attributes = new Collection ()); + } + } + + internal bool HasImage { + get { return module != null && module.HasImage; } + } + + internal SecurityDeclaration (SecurityAction action, uint signature, ModuleDefinition module) + { + this.action = action; + this.signature = signature; + this.module = module; + } + + public SecurityDeclaration (SecurityAction action) + { + this.action = action; + this.resolved = true; + } + + public byte [] GetBlob () + { + if (!HasImage || signature == 0) + throw new NotSupportedException (); + + return module.Read (this, (declaration, reader) => reader.ReadSecurityDeclarationBlob (declaration.signature)); ; + } + + void Resolve () + { + if (resolved || !HasImage) + return; + + module.Read (this, (declaration, reader) => { + reader.ReadSecurityDeclarationSignature (declaration); + return this; + }); + + resolved = true; + } + } + + static partial class Mixin { + + public static bool GetHasSecurityDeclarations ( + this ISecurityDeclarationProvider self, + ModuleDefinition module) + { + return module.HasImage () + ? module.Read (self, (provider, reader) => reader.HasSecurityDeclarations (provider)) + : false; + } + + public static Collection GetSecurityDeclarations ( + this ISecurityDeclarationProvider self, + ModuleDefinition module) + { + return module.HasImage () + ? module.Read (self, (provider, reader) => reader.ReadSecurityDeclarations (provider)) + : new Collection (); + } + } +} diff --git a/Mono.Cecil/SentinelType.cs b/Mono.Cecil/SentinelType.cs new file mode 100644 index 000000000..d0d5a1d1e --- /dev/null +++ b/Mono.Cecil/SentinelType.cs @@ -0,0 +1,53 @@ +// +// SentinelType.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +using MD = Mono.Cecil.Metadata; + +namespace Mono.Cecil { + + public sealed class SentinelType : TypeSpecification { + + public override bool IsValueType { + get { return false; } + set { throw new InvalidOperationException (); } + } + + public override bool IsSentinel { + get { return true; } + } + + public SentinelType (TypeReference type) + : base (type) + { + Mixin.CheckType (type); + this.etype = MD.ElementType.Sentinel; + } + } +} diff --git a/Mono.Cecil/TargetRuntime.cs b/Mono.Cecil/TargetRuntime.cs new file mode 100644 index 000000000..9931fc611 --- /dev/null +++ b/Mono.Cecil/TargetRuntime.cs @@ -0,0 +1,37 @@ +// +// TargetRuntime.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace Mono.Cecil { + + public enum TargetRuntime { + Net_1_0, + Net_1_1, + Net_2_0, + Net_4_0, + } +} diff --git a/Mono.Cecil/TypeAttributes.cs b/Mono.Cecil/TypeAttributes.cs new file mode 100644 index 000000000..6e263e8e6 --- /dev/null +++ b/Mono.Cecil/TypeAttributes.cs @@ -0,0 +1,80 @@ +// +// TypeAttributes.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace Mono.Cecil { + + [Flags] + public enum TypeAttributes : uint { + // Visibility attributes + VisibilityMask = 0x00000007, // Use this mask to retrieve visibility information + NotPublic = 0x00000000, // Class has no public scope + Public = 0x00000001, // Class has public scope + NestedPublic = 0x00000002, // Class is nested with public visibility + NestedPrivate = 0x00000003, // Class is nested with private visibility + NestedFamily = 0x00000004, // Class is nested with family visibility + NestedAssembly = 0x00000005, // Class is nested with assembly visibility + NestedFamANDAssem = 0x00000006, // Class is nested with family and assembly visibility + NestedFamORAssem = 0x00000007, // Class is nested with family or assembly visibility + + // Class layout attributes + LayoutMask = 0x00000018, // Use this mask to retrieve class layout information + AutoLayout = 0x00000000, // Class fields are auto-laid out + SequentialLayout = 0x00000008, // Class fields are laid out sequentially + ExplicitLayout = 0x00000010, // Layout is supplied explicitly + + // Class semantics attributes + ClassSemanticMask = 0x00000020, // Use this mask to retrieve class semantics information + Class = 0x00000000, // Type is a class + Interface = 0x00000020, // Type is an interface + + // Special semantics in addition to class semantics + Abstract = 0x00000080, // Class is abstract + Sealed = 0x00000100, // Class cannot be extended + SpecialName = 0x00000400, // Class name is special + + // Implementation attributes + Import = 0x00001000, // Class/Interface is imported + Serializable = 0x00002000, // Class is serializable + + // String formatting attributes + StringFormatMask = 0x00030000, // Use this mask to retrieve string information for native interop + AnsiClass = 0x00000000, // LPSTR is interpreted as ANSI + UnicodeClass = 0x00010000, // LPSTR is interpreted as Unicode + AutoClass = 0x00020000, // LPSTR is interpreted automatically + + // Class initialization attributes + BeforeFieldInit = 0x00100000, // Initialize the class before first static field access + + // Additional flags + RTSpecialName = 0x00000800, // CLI provides 'special' behavior, depending upon the name of the Type + HasSecurity = 0x00040000, // Type has security associate with it + Forwarder = 0x00200000, // Exported type is a type forwarder + } +} diff --git a/Mono.Cecil/TypeDefinition.cs b/Mono.Cecil/TypeDefinition.cs new file mode 100644 index 000000000..c83531a05 --- /dev/null +++ b/Mono.Cecil/TypeDefinition.cs @@ -0,0 +1,499 @@ +// +// TypeDefinition.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +using Mono.Collections.Generic; + +namespace Mono.Cecil { + + public sealed class TypeDefinition : TypeReference, IMemberDefinition, ISecurityDeclarationProvider { + + uint attributes; + TypeReference base_type; + internal Range fields_range; + internal Range methods_range; + + short packing_size = Mixin.NotResolvedMarker; + int class_size = Mixin.NotResolvedMarker; + + Collection interfaces; + Collection nested_types; + Collection methods; + Collection fields; + Collection events; + Collection properties; + Collection custom_attributes; + Collection security_declarations; + + public TypeAttributes Attributes { + get { return (TypeAttributes) attributes; } + set { attributes = (uint) value; } + } + + public TypeReference BaseType { + get { return base_type; } + set { base_type = value; } + } + + void ResolveLayout () + { + if (packing_size != Mixin.NotResolvedMarker || class_size != Mixin.NotResolvedMarker) + return; + + if (!HasImage) { + packing_size = Mixin.NoDataMarker; + class_size = Mixin.NoDataMarker; + return; + } + + var row = Module.Read (this, (type, reader) => reader.ReadTypeLayout (type)); + + packing_size = row.Col1; + class_size = row.Col2; + } + + public bool HasLayoutInfo { + get { + if (packing_size >= 0 || class_size >= 0) + return true; + + ResolveLayout (); + + return packing_size >= 0 || class_size >= 0; + } + } + + public short PackingSize { + get { + if (packing_size >= 0) + return packing_size; + + ResolveLayout (); + + return packing_size >= 0 ? packing_size : (short) -1; + } + set { packing_size = value; } + } + + public int ClassSize { + get { + if (class_size >= 0) + return class_size; + + ResolveLayout (); + + return class_size >= 0 ? class_size : -1; + } + set { class_size = value; } + } + + public bool HasInterfaces { + get { + if (interfaces != null) + return interfaces.Count > 0; + + if (HasImage) + return Module.Read (this, (type, reader) => reader.HasInterfaces (type)); + + return false; + } + } + + public Collection Interfaces { + get { + if (interfaces != null) + return interfaces; + + if (HasImage) + return interfaces = Module.Read (this, (type, reader) => reader.ReadInterfaces (type)); + + return interfaces = new Collection (); + } + } + + public bool HasNestedTypes { + get { + if (nested_types != null) + return nested_types.Count > 0; + + if (HasImage) + return Module.Read (this, (type, reader) => reader.HasNestedTypes (type)); + + return false; + } + } + + public Collection NestedTypes { + get { + if (nested_types != null) + return nested_types; + + if (HasImage) + return nested_types = Module.Read (this, (type, reader) => reader.ReadNestedTypes (type)); + + return nested_types = new MemberDefinitionCollection (this); + } + } + + internal new bool HasImage { + get { return Module != null && Module.HasImage; } + } + + public bool HasMethods { + get { + if (methods != null) + return methods.Count > 0; + + if (HasImage) + return methods_range.Length > 0; + + return false; + } + } + + public Collection Methods { + get { + if (methods != null) + return methods; + + if (HasImage) + return methods = Module.Read (this, (type, reader) => reader.ReadMethods (type)); + + return methods = new MemberDefinitionCollection (this); + } + } + + public bool HasFields { + get { + if (fields != null) + return fields.Count > 0; + + if (HasImage) + return fields_range.Length > 0; + + return false; + } + } + + public Collection Fields { + get { + if (fields != null) + return fields; + + if (HasImage) + return fields = Module.Read (this, (type, reader) => reader.ReadFields (type)); + + return fields = new MemberDefinitionCollection (this); + } + } + + public bool HasEvents { + get { + if (events != null) + return events.Count > 0; + + if (HasImage) + return Module.Read (this, (type, reader) => reader.HasEvents (type)); + + return false; + } + } + + public Collection Events { + get { + if (events != null) + return events; + + if (HasImage) + return events = Module.Read (this, (type, reader) => reader.ReadEvents (type)); + + return events = new MemberDefinitionCollection (this); + } + } + + public bool HasProperties { + get { + if (properties != null) + return properties.Count > 0; + + if (HasImage) + return Module.Read (this, (type, reader) => reader.HasProperties (type)); + + return false; + } + } + + public Collection Properties { + get { + if (properties != null) + return properties; + + if (HasImage) + return properties = Module.Read (this, (type, reader) => reader.ReadProperties (type)); + + return properties = new MemberDefinitionCollection (this); + } + } + + public bool HasSecurityDeclarations { + get { + if (security_declarations != null) + return security_declarations.Count > 0; + + return this.GetHasSecurityDeclarations (Module); + } + } + + public Collection SecurityDeclarations { + get { return security_declarations ?? (security_declarations = this.GetSecurityDeclarations (Module)); } + } + + public bool HasCustomAttributes { + get { + if (custom_attributes != null) + return custom_attributes.Count > 0; + + return this.GetHasCustomAttributes (Module); + } + } + + public Collection CustomAttributes { + get { return custom_attributes ?? (custom_attributes = this.GetCustomAttributes (Module)); } + } + + public override bool HasGenericParameters { + get { + if (generic_parameters != null) + return generic_parameters.Count > 0; + + return this.GetHasGenericParameters (Module); + } + } + + public override Collection GenericParameters { + get { return generic_parameters ?? (generic_parameters = this.GetGenericParameters (Module)); } + } + + #region TypeAttributes + + public bool IsNotPublic { + get { return attributes.GetMaskedAttributes ((uint) TypeAttributes.VisibilityMask, (uint) TypeAttributes.NotPublic); } + set { attributes = attributes.SetMaskedAttributes ((uint) TypeAttributes.VisibilityMask, (uint) TypeAttributes.NotPublic, value); } + } + + public bool IsPublic { + get { return attributes.GetMaskedAttributes ((uint) TypeAttributes.VisibilityMask, (uint) TypeAttributes.Public); } + set { attributes = attributes.SetMaskedAttributes ((uint) TypeAttributes.VisibilityMask, (uint) TypeAttributes.Public, value); } + } + + public bool IsNestedPublic { + get { return attributes.GetMaskedAttributes ((uint) TypeAttributes.VisibilityMask, (uint) TypeAttributes.NestedPublic); } + set { attributes = attributes.SetMaskedAttributes ((uint) TypeAttributes.VisibilityMask, (uint) TypeAttributes.NestedPublic, value); } + } + + public bool IsNestedPrivate { + get { return attributes.GetMaskedAttributes ((uint) TypeAttributes.VisibilityMask, (uint) TypeAttributes.NestedPrivate); } + set { attributes = attributes.SetMaskedAttributes ((uint) TypeAttributes.VisibilityMask, (uint) TypeAttributes.NestedPrivate, value); } + } + + public bool IsNestedFamily { + get { return attributes.GetMaskedAttributes ((uint) TypeAttributes.VisibilityMask, (uint) TypeAttributes.NestedFamily); } + set { attributes = attributes.SetMaskedAttributes ((uint) TypeAttributes.VisibilityMask, (uint) TypeAttributes.NestedFamily, value); } + } + + public bool IsNestedAssembly { + get { return attributes.GetMaskedAttributes ((uint) TypeAttributes.VisibilityMask, (uint) TypeAttributes.NestedAssembly); } + set { attributes = attributes.SetMaskedAttributes ((uint) TypeAttributes.VisibilityMask, (uint) TypeAttributes.NestedAssembly, value); } + } + + public bool IsNestedFamilyAndAssembly { + get { return attributes.GetMaskedAttributes ((uint) TypeAttributes.VisibilityMask, (uint) TypeAttributes.NestedFamANDAssem); } + set { attributes = attributes.SetMaskedAttributes ((uint) TypeAttributes.VisibilityMask, (uint) TypeAttributes.NestedFamANDAssem, value); } + } + + public bool IsNestedFamilyOrAssembly { + get { return attributes.GetMaskedAttributes ((uint) TypeAttributes.VisibilityMask, (uint) TypeAttributes.NestedFamORAssem); } + set { attributes = attributes.SetMaskedAttributes ((uint) TypeAttributes.VisibilityMask, (uint) TypeAttributes.NestedFamORAssem, value); } + } + + public bool IsAutoLayout { + get { return attributes.GetMaskedAttributes ((uint) TypeAttributes.LayoutMask, (uint) TypeAttributes.AutoLayout); } + set { attributes = attributes.SetMaskedAttributes ((uint) TypeAttributes.LayoutMask, (uint) TypeAttributes.AutoLayout, value); } + } + + public bool IsSequentialLayout { + get { return attributes.GetMaskedAttributes ((uint) TypeAttributes.LayoutMask, (uint) TypeAttributes.SequentialLayout); } + set { attributes = attributes.SetMaskedAttributes ((uint) TypeAttributes.LayoutMask, (uint) TypeAttributes.SequentialLayout, value); } + } + + public bool IsExplicitLayout { + get { return attributes.GetMaskedAttributes ((uint) TypeAttributes.LayoutMask, (uint) TypeAttributes.ExplicitLayout); } + set { attributes = attributes.SetMaskedAttributes ((uint) TypeAttributes.LayoutMask, (uint) TypeAttributes.ExplicitLayout, value); } + } + + public bool IsClass { + get { return attributes.GetMaskedAttributes ((uint) TypeAttributes.ClassSemanticMask, (uint) TypeAttributes.Class); } + set { attributes = attributes.SetMaskedAttributes ((uint) TypeAttributes.ClassSemanticMask, (uint) TypeAttributes.Class, value); } + } + + public bool IsInterface { + get { return attributes.GetMaskedAttributes ((uint) TypeAttributes.ClassSemanticMask, (uint) TypeAttributes.Interface); } + set { attributes = attributes.SetMaskedAttributes ((uint) TypeAttributes.ClassSemanticMask, (uint) TypeAttributes.Interface, value); } + } + + public bool IsAbstract { + get { return attributes.GetAttributes ((uint) TypeAttributes.Abstract); } + set { attributes = attributes.SetAttributes ((uint) TypeAttributes.Abstract, value); } + } + + public bool IsSealed { + get { return attributes.GetAttributes ((uint) TypeAttributes.Sealed); } + set { attributes = attributes.SetAttributes ((uint) TypeAttributes.Sealed, value); } + } + + public bool IsSpecialName { + get { return attributes.GetAttributes ((uint) TypeAttributes.SpecialName); } + set { attributes = attributes.SetAttributes ((uint) TypeAttributes.SpecialName, value); } + } + + public bool IsImport { + get { return attributes.GetAttributes ((uint) TypeAttributes.Import); } + set { attributes = attributes.SetAttributes ((uint) TypeAttributes.Import, value); } + } + + public bool IsSerializable { + get { return attributes.GetAttributes ((uint) TypeAttributes.Serializable); } + set { attributes = attributes.SetAttributes ((uint) TypeAttributes.Serializable, value); } + } + + public bool IsAnsiClass { + get { return attributes.GetMaskedAttributes ((uint) TypeAttributes.StringFormatMask, (uint) TypeAttributes.AnsiClass); } + set { attributes = attributes.SetMaskedAttributes ((uint) TypeAttributes.StringFormatMask, (uint) TypeAttributes.AnsiClass, value); } + } + + public bool IsUnicodeClass { + get { return attributes.GetMaskedAttributes ((uint) TypeAttributes.StringFormatMask, (uint) TypeAttributes.UnicodeClass); } + set { attributes = attributes.SetMaskedAttributes ((uint) TypeAttributes.StringFormatMask, (uint) TypeAttributes.UnicodeClass, value); } + } + + public bool IsAutoClass { + get { return attributes.GetMaskedAttributes ((uint) TypeAttributes.StringFormatMask, (uint) TypeAttributes.AutoClass); } + set { attributes = attributes.SetMaskedAttributes ((uint) TypeAttributes.StringFormatMask, (uint) TypeAttributes.AutoClass, value); } + } + + public bool IsBeforeFieldInit { + get { return attributes.GetAttributes ((uint) TypeAttributes.BeforeFieldInit); } + set { attributes = attributes.SetAttributes ((uint) TypeAttributes.BeforeFieldInit, value); } + } + + public bool IsRuntimeSpecialName { + get { return attributes.GetAttributes ((uint) TypeAttributes.RTSpecialName); } + set { attributes = attributes.SetAttributes ((uint) TypeAttributes.RTSpecialName, value); } + } + + public bool HasSecurity { + get { return attributes.GetAttributes ((uint) TypeAttributes.HasSecurity); } + set { attributes = attributes.SetAttributes ((uint) TypeAttributes.HasSecurity, value); } + } + + #endregion + + public bool IsEnum { + get { return base_type != null && base_type.IsTypeOf ("System", "Enum"); } + } + + public override bool IsValueType { + get { + if (base_type == null) + return false; + + return base_type.IsTypeOf ("System", "Enum") || (base_type.IsTypeOf ("System", "ValueType") && !this.IsTypeOf ("System", "Enum")); + } + } + + public override bool IsDefinition { + get { return true; } + } + + public new TypeDefinition DeclaringType { + get { return (TypeDefinition) base.DeclaringType; } + set { base.DeclaringType = value; } + } + + public TypeDefinition (string @namespace, string name, TypeAttributes attributes) + : base (@namespace, name) + { + this.attributes = (uint) attributes; + this.token = new MetadataToken (TokenType.TypeDef); + } + + public TypeDefinition (string @namespace, string name, TypeAttributes attributes, TypeReference baseType) : + this (@namespace, name, attributes) + { + this.BaseType = baseType; + } + + public override TypeDefinition Resolve () + { + return this; + } + } + + static partial class Mixin { + + public static TypeReference GetEnumUnderlyingType (this TypeDefinition self) + { + var fields = self.Fields; + + for (int i = 0; i < fields.Count; i++) { + var field = fields [i]; + if (!field.IsStatic) + return field.FieldType; + } + + throw new ArgumentException (); + } + + public static TypeDefinition GetNestedType (this TypeDefinition self, string name) + { + if (!self.HasNestedTypes) + return null; + + var nested_types = self.NestedTypes; + + for (int i = 0; i < nested_types.Count; i++) { + var nested_type = nested_types [i]; + if (nested_type.Name == name) + return nested_type; + } + + return null; + } + } +} diff --git a/Mono.Cecil/TypeDefinitionCollection.cs b/Mono.Cecil/TypeDefinitionCollection.cs new file mode 100644 index 000000000..702fe271e --- /dev/null +++ b/Mono.Cecil/TypeDefinitionCollection.cs @@ -0,0 +1,118 @@ +// +// TypeDefinitionCollection.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Generic; + +using Mono.Cecil.Metadata; + +using Mono.Collections.Generic; + +namespace Mono.Cecil { + + using Slot = Row; + + sealed class TypeDefinitionCollection : Collection { + + readonly ModuleDefinition container; + readonly Dictionary name_cache; + + internal TypeDefinitionCollection (ModuleDefinition container) + { + this.container = container; + this.name_cache = new Dictionary (new RowEqualityComparer ()); + } + + internal TypeDefinitionCollection (ModuleDefinition container, int capacity) + : base (capacity) + { + this.container = container; + this.name_cache = new Dictionary (capacity, new RowEqualityComparer ()); + } + + protected override void OnAdd (TypeDefinition item, int index) + { + Attach (item); + } + + protected override void OnSet (TypeDefinition item, int index) + { + Attach (item); + } + + protected override void OnInsert (TypeDefinition item, int index) + { + Attach (item); + } + + protected override void OnRemove (TypeDefinition item, int index) + { + Detach (item); + } + + protected override void OnClear () + { + foreach (var type in this) + Detach (type); + } + + void Attach (TypeDefinition type) + { + if (type.Module != null && type.Module != container) + throw new ArgumentException ("Type already attached"); + + type.module = container; + type.scope = container; + name_cache [new Slot (type.Namespace, type.Name)] = type; + } + + void Detach (TypeDefinition type) + { + type.module = null; + type.scope = null; + name_cache.Remove (new Slot (type.Namespace, type.Name)); + } + + public TypeDefinition GetType (string fullname) + { + string @namespace, name; + TypeParser.SplitFullName (fullname, out @namespace, out name); + + return GetType (@namespace, name); + } + + public TypeDefinition GetType (string @namespace, string name) + { + TypeDefinition type; + if (name_cache.TryGetValue (new Slot (@namespace, name), out type)) + return type; + + return null; + } + } +} diff --git a/Mono.Cecil/TypeParser.cs b/Mono.Cecil/TypeParser.cs new file mode 100644 index 000000000..4da4d6be1 --- /dev/null +++ b/Mono.Cecil/TypeParser.cs @@ -0,0 +1,555 @@ +// +// TypeParser.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Text; + +using Mono.Cecil.Metadata; + +namespace Mono.Cecil { + + class TypeParser { + + class Type { + public const int Ptr = -1; + public const int ByRef = -2; + public const int SzArray = -3; + + public string type_fullname; + public string [] nested_names; + public int arity; + public int [] specs; + public Type [] generic_arguments; + public string assembly; + } + + readonly string fullname; + readonly int length; + + int position; + + TypeParser (string fullname) + { + this.fullname = fullname; + this.length = fullname.Length; + } + + Type ParseType (bool fq_name) + { + var type = new Type (); + type.type_fullname = ParsePart (); + + type.nested_names = ParseNestedNames (); + + if (TryGetArity (type)) + type.generic_arguments = ParseGenericArguments (type.arity); + + type.specs = ParseSpecs (); + + if (fq_name) + type.assembly = ParseAssemblyName (); + + return type; + } + + static bool TryGetArity (Type type) + { + int arity = 0; + + TryAddArity (type.type_fullname, ref arity); + + var nested_names = type.nested_names; + if (!nested_names.IsNullOrEmpty ()) { + for (int i = 0; i < nested_names.Length; i++) + TryAddArity (nested_names [i], ref arity); + } + + type.arity = arity; + return arity > 0; + } + + static bool TryGetArity (string name, out int arity) + { + arity = 0; + var index = name.LastIndexOf ('`'); + if (index == -1) + return false; + + return ParseInt32 (name.Substring (index + 1), out arity); + } + + static bool ParseInt32 (string value, out int result) + { +#if CF + try { + result = int.Parse (value); + return true; + } catch { + result = 0; + return false; + } +#else + return int.TryParse (value, out result); +#endif + } + + static void TryAddArity (string name, ref int arity) + { + int type_arity; + if (!TryGetArity (name, out type_arity)) + return; + + arity += type_arity; + } + + string ParsePart () + { + int start = position; + while (position < length && !IsDelimiter (fullname [position])) + position++; + + return fullname.Substring (start, position - start); + } + + static bool IsDelimiter (char chr) + { + return "+,[]*&".IndexOf (chr) != -1; + } + + void TryParseWhiteSpace () + { + while (position < length && Char.IsWhiteSpace (fullname [position])) + position++; + } + + string [] ParseNestedNames () + { + string [] nested_names = null; + while (TryParse ('+')) + Add (ref nested_names, ParsePart ()); + + return nested_names; + } + + bool TryParse (char chr) + { + if (position < length && fullname [position] == chr) { + position++; + return true; + } + + return false; + } + + static void Add (ref T [] array, T item) + { + if (array == null) { + array = new [] { item }; + return; + } + +#if !CF + Array.Resize (ref array, array.Length + 1); +#else + var copy = new T [array.Length + 1]; + Array.Copy (array, copy, array.Length); + array = copy; +#endif + array [array.Length - 1] = item; + } + + int [] ParseSpecs () + { + int [] specs = null; + + while (position < length) { + switch (fullname [position]) { + case '*': + position++; + Add (ref specs, Type.Ptr); + break; + case '&': + position++; + Add (ref specs, Type.ByRef); + break; + case '[': + position++; + switch (fullname [position]) { + case ']': + position++; + Add (ref specs, Type.SzArray); + break; + case '*': + position++; + Add (ref specs, 1); + break; + default: + var rank = 1; + while (TryParse (',')) + rank++; + + Add (ref specs, rank); + + TryParse (']'); + break; + } + break; + default: + return specs; + } + } + + return specs; + } + + Type [] ParseGenericArguments (int arity) + { + Type [] generic_arguments = null; + + if (position == length || fullname [position] != '[') + return generic_arguments; + + TryParse ('['); + + for (int i = 0; i < arity; i++) { + var fq_argument = TryParse ('['); + Add (ref generic_arguments, ParseType (fq_argument)); + if (fq_argument) + TryParse (']'); + + TryParse (','); + TryParseWhiteSpace (); + } + + TryParse (']'); + + return generic_arguments; + } + + string ParseAssemblyName () + { + if (!TryParse (',')) + return string.Empty; + + TryParseWhiteSpace (); + + var start = position; + while (position < length) { + var chr = fullname [position]; + if (chr == '[' || chr == ']') + break; + + position++; + } + + return fullname.Substring (start, position - start); + } + + public static TypeReference ParseType (ModuleDefinition module, string fullname) + { + if (fullname == null) + return null; + + var parser = new TypeParser (fullname); + return GetTypeReference (module, parser.ParseType (true)); + } + + static TypeReference GetTypeReference (ModuleDefinition module, Type type_info) + { + TypeReference type; + if (!TryGetDefinition (module, type_info, out type)) + type = CreateReference (type_info, module, GetMetadataScope (module, type_info)); + + return CreateSpecs (type, type_info); + } + + static TypeReference CreateSpecs (TypeReference type, Type type_info) + { + type = TryCreateGenericInstanceType (type, type_info); + + var specs = type_info.specs; + if (specs.IsNullOrEmpty ()) + return type; + + for (int i = 0; i < specs.Length; i++) { + switch (specs [i]) { + case Type.Ptr: + type = new PointerType (type); + break; + case Type.ByRef: + type = new ByReferenceType (type); + break; + case Type.SzArray: + type = new ArrayType (type); + break; + default: + var array = new ArrayType (type); + array.Dimensions.Clear (); + + for (int j = 0; j < specs [i]; j++) + array.Dimensions.Add (new ArrayDimension ()); + + type = array; + break; + } + } + + return type; + } + + static TypeReference TryCreateGenericInstanceType (TypeReference type, Type type_info) + { + var generic_arguments = type_info.generic_arguments; + if (generic_arguments.IsNullOrEmpty ()) + return type; + + var instance = new GenericInstanceType (type); + var instance_arguments = instance.GenericArguments; + + for (int i = 0; i < generic_arguments.Length; i++) + instance_arguments.Add (GetTypeReference (type.Module, generic_arguments [i])); + + return instance; + } + + public static void SplitFullName (string fullname, out string @namespace, out string name) + { + var last_dot = fullname.LastIndexOf ('.'); + + if (last_dot == -1) { + @namespace = string.Empty; + name = fullname; + } else { + @namespace = fullname.Substring (0, last_dot); + name = fullname.Substring (last_dot + 1); + } + } + + static TypeReference CreateReference (Type type_info, ModuleDefinition module, IMetadataScope scope) + { + string @namespace, name; + SplitFullName (type_info.type_fullname, out @namespace, out name); + + var type = new TypeReference (@namespace, name, module, scope); + MetadataSystem.TryProcessPrimitiveType (type); + + AdjustGenericParameters (type); + + var nested_names = type_info.nested_names; + if (nested_names.IsNullOrEmpty ()) + return type; + + for (int i = 0; i < nested_names.Length; i++) { + type = new TypeReference (string.Empty, nested_names [i], module, null) { + DeclaringType = type, + }; + + AdjustGenericParameters (type); + } + + return type; + } + + static void AdjustGenericParameters (TypeReference type) + { + int arity; + if (!TryGetArity (type.Name, out arity)) + return; + + for (int i = 0; i < arity; i++) + type.GenericParameters.Add (new GenericParameter (type)); + } + + static IMetadataScope GetMetadataScope (ModuleDefinition module, Type type_info) + { + if (string.IsNullOrEmpty (type_info.assembly)) + return module.TypeSystem.Corlib; + + return MatchReference (module, AssemblyNameReference.Parse (type_info.assembly)); + } + + static AssemblyNameReference MatchReference (ModuleDefinition module, AssemblyNameReference pattern) + { + var references = module.AssemblyReferences; + + for (int i = 0; i < references.Count; i++) { + var reference = references [i]; + if (reference.FullName == pattern.FullName) + return reference; + } + + return pattern; + } + + static bool TryGetDefinition (ModuleDefinition module, Type type_info, out TypeReference type) + { + type = null; + if (!TryCurrentModule (module, type_info)) + return false; + + var typedef = module.GetType (type_info.type_fullname); + if (typedef == null) + return false; + + var nested_names = type_info.nested_names; + if (!nested_names.IsNullOrEmpty ()) { + for (int i = 0; i < nested_names.Length; i++) + typedef = typedef.GetNestedType (nested_names [i]); + } + + type = typedef; + return true; + } + + static bool TryCurrentModule (ModuleDefinition module, Type type_info) + { + if (string.IsNullOrEmpty (type_info.assembly)) + return true; + + if (module.assembly != null && module.assembly.Name.FullName == type_info.assembly) + return true; + + return false; + } + + public static string ToParseable (TypeReference type) + { + if (type == null) + return null; + + var name = new StringBuilder (); + AppendType (type, name, true, true); + return name.ToString (); + } + + static void AppendType (TypeReference type, StringBuilder name, bool fq_name, bool top_level) + { + var declaring_type = type.DeclaringType; + if (declaring_type != null) { + AppendType (declaring_type, name, false, top_level); + name.Append ('+'); + } + + var @namespace = type.Namespace; + if (!string.IsNullOrEmpty (@namespace)) { + name.Append (@namespace); + name.Append ('.'); + } + + name.Append (type.GetElementType ().Name); + + if (!fq_name) + return; + + if (type.IsTypeSpecification ()) + AppendTypeSpecification ((TypeSpecification) type, name); + + if (RequiresFullyQualifiedName (type, top_level)) { + name.Append (", "); + name.Append (GetScopeFullName (type)); + } + } + + static string GetScopeFullName (TypeReference type) + { + var scope = type.Scope; + switch (scope.MetadataScopeType) { + case MetadataScopeType.AssemblyNameReference: + return ((AssemblyNameReference) scope).FullName; + case MetadataScopeType.ModuleDefinition: + return ((ModuleDefinition) scope).Assembly.Name.FullName; + } + + throw new ArgumentException (); + } + + static void AppendTypeSpecification (TypeSpecification type, StringBuilder name) + { + if (type.ElementType.IsTypeSpecification ()) + AppendTypeSpecification ((TypeSpecification) type.ElementType, name); + + switch (type.etype) { + case ElementType.Ptr: + name.Append ('*'); + break; + case ElementType.ByRef: + name.Append ('&'); + break; + case ElementType.SzArray: + case ElementType.Array: + var array = (ArrayType) type; + if (array.IsVector) { + name.Append ("[]"); + } else { + name.Append ('['); + for (int i = 1; i < array.Rank; i++) + name.Append (','); + name.Append (']'); + } + break; + case ElementType.GenericInst: + var instance = (GenericInstanceType) type; + var arguments = instance.GenericArguments; + + name.Append ('['); + + for (int i = 0; i < arguments.Count; i++) { + if (i > 0) + name.Append (','); + + var argument = arguments [i]; + var requires_fqname = argument.Scope != argument.Module; + + if (requires_fqname) + name.Append ('['); + + AppendType (argument, name, true, false); + + if (requires_fqname) + name.Append (']'); + } + + name.Append (']'); + break; + default: + return; + } + } + + static bool RequiresFullyQualifiedName (TypeReference type, bool top_level) + { + if (type.Scope == type.Module) + return false; + + if (type.Scope.Name == "mscorlib" && top_level) + return false; + + return true; + } + } +} diff --git a/Mono.Cecil/TypeReference.cs b/Mono.Cecil/TypeReference.cs new file mode 100644 index 000000000..596ae6994 --- /dev/null +++ b/Mono.Cecil/TypeReference.cs @@ -0,0 +1,327 @@ +// +// TypeReference.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +using Mono.Cecil.Metadata; +using Mono.Collections.Generic; + +namespace Mono.Cecil { + + public enum MetadataType : byte { + Void = ElementType.Void, + Boolean = ElementType.Boolean, + Char = ElementType.Char, + SByte = ElementType.I1, + Byte = ElementType.U1, + Int16 = ElementType.I2, + UInt16 = ElementType.U2, + Int32 = ElementType.I4, + UInt32 = ElementType.U4, + Int64 = ElementType.I8, + UInt64 = ElementType.U8, + Single = ElementType.R4, + Double = ElementType.R8, + String = ElementType.String, + Pointer = ElementType.Ptr, + ByReference = ElementType.ByRef, + ValueType = ElementType.ValueType, + Class = ElementType.Class, + Var = ElementType.Var, + Array = ElementType.Array, + GenericInstance = ElementType.GenericInst, + TypedByReference = ElementType.TypedByRef, + IntPtr = ElementType.I, + UIntPtr = ElementType.U, + FunctionPointer = ElementType.FnPtr, + Object = ElementType.Object, + MVar = ElementType.MVar, + RequiredModifier = ElementType.CModReqD, + OptionalModifier = ElementType.CModOpt, + Sentinel = ElementType.Sentinel, + Pinned = ElementType.Pinned, + } + + public class TypeReference : MemberReference, IGenericParameterProvider, IGenericContext { + + string @namespace; + bool value_type; + internal IMetadataScope scope; + internal ModuleDefinition module; + + internal ElementType etype = ElementType.None; + + string fullname; + + protected Collection generic_parameters; + + public override string Name { + get { return base.Name; } + set { + base.Name = value; + fullname = null; + } + } + + public virtual string Namespace { + get { return @namespace; } + set { + @namespace = value; + fullname = null; + } + } + + public virtual bool IsValueType { + get { return value_type; } + set { value_type = value; } + } + + public override ModuleDefinition Module { + get { + if (module != null) + return module; + + var declaring_type = this.DeclaringType; + if (declaring_type != null) + return declaring_type.Module; + + return null; + } + } + + IGenericParameterProvider IGenericContext.Type { + get { return this; } + } + + IGenericParameterProvider IGenericContext.Method { + get { return null; } + } + + GenericParameterType IGenericParameterProvider.GenericParameterType { + get { return GenericParameterType.Type; } + } + + public virtual bool HasGenericParameters { + get { return !generic_parameters.IsNullOrEmpty (); } + } + + public virtual Collection GenericParameters { + get { + if (generic_parameters != null) + return generic_parameters; + + return generic_parameters = new Collection (); + } + } + + public virtual IMetadataScope Scope { + get { + var declaring_type = this.DeclaringType; + if (declaring_type != null) + return declaring_type.Scope; + + return scope; + } + } + + public bool IsNested { + get { return this.DeclaringType != null; } + } + + public override TypeReference DeclaringType { + get { return base.DeclaringType; } + set { + base.DeclaringType = value; + fullname = null; + } + } + + public override string FullName { + get { + if (fullname != null) + return fullname; + + if (IsNested) + return fullname = DeclaringType.FullName + "/" + Name; + + if (string.IsNullOrEmpty (@namespace)) + return fullname = Name; + + return fullname = @namespace + "." + Name; + } + } + + public virtual bool IsByReference { + get { return false; } + } + + public virtual bool IsPointer { + get { return false; } + } + + public virtual bool IsSentinel { + get { return false; } + } + + public virtual bool IsArray { + get { return false; } + } + + public virtual bool IsGenericParameter { + get { return false; } + } + + public virtual bool IsGenericInstance { + get { return false; } + } + + public virtual bool IsRequiredModifier { + get { return false; } + } + + public virtual bool IsOptionalModifier { + get { return false; } + } + + public virtual bool IsPinned { + get { return false; } + } + + public virtual bool IsFunctionPointer { + get { return false; } + } + + public bool IsPrimitive { + get { + switch (etype) { + case ElementType.Boolean: + case ElementType.Char: + case ElementType.I: + case ElementType.U: + case ElementType.I1: + case ElementType.U1: + case ElementType.I2: + case ElementType.U2: + case ElementType.I4: + case ElementType.U4: + case ElementType.I8: + case ElementType.U8: + case ElementType.R4: + case ElementType.R8: + return true; + default: + return false; + } + } + } + + public virtual MetadataType MetadataType { + get { + switch (etype) { + case ElementType.None: + return IsValueType ? MetadataType.ValueType : MetadataType.Class; + default: + return (MetadataType) etype; + } + } + } + + protected TypeReference (string @namespace, string name) + : base (name) + { + this.@namespace = @namespace ?? string.Empty; + this.token = new MetadataToken (TokenType.TypeRef, 0); + } + + public TypeReference (string @namespace, string name, ModuleDefinition module, IMetadataScope scope) + : this (@namespace, name) + { + this.module = module; + this.scope = scope; + } + + public TypeReference (string @namespace, string name, ModuleDefinition module, IMetadataScope scope, bool valueType) : + this (@namespace, name, module, scope) + { + value_type = valueType; + } + + public virtual TypeReference GetElementType () + { + return this; + } + + public virtual TypeDefinition Resolve () + { + var module = this.Module; + if (module == null) + throw new NotSupportedException (); + + return module.Resolve (this); + } + } + + static partial class Mixin { + + public static bool IsTypeOf (this TypeReference self, string @namespace, string name) + { + return self.Name == name + && self.Namespace == @namespace; + } + + public static bool IsTypeSpecification (this TypeReference type) + { + switch (type.etype) { + case ElementType.Array: + case ElementType.ByRef: + case ElementType.CModOpt: + case ElementType.CModReqD: + case ElementType.FnPtr: + case ElementType.GenericInst: + case ElementType.MVar: + case ElementType.Pinned: + case ElementType.Ptr: + case ElementType.SzArray: + case ElementType.Sentinel: + case ElementType.Var: + return true; + } + + return false; + } + + public static TypeDefinition CheckedResolve (this TypeReference self) + { + var type = self.Resolve (); + if (type == null) + throw new ResolutionException (self); + + return type; + } + } +} diff --git a/Mono.Cecil/TypeSpecification.cs b/Mono.Cecil/TypeSpecification.cs new file mode 100644 index 000000000..da4e72643 --- /dev/null +++ b/Mono.Cecil/TypeSpecification.cs @@ -0,0 +1,94 @@ +// +// TypeSpecification.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +using Mono.Cecil.Metadata; + +namespace Mono.Cecil { + + public abstract class TypeSpecification : TypeReference { + + readonly TypeReference element_type; + + public TypeReference ElementType { + get { return element_type; } + } + + public override string Name { + get { return element_type.Name; } + set { throw new NotSupportedException (); } + } + + public override string Namespace { + get { return element_type.Namespace; } + set { throw new NotSupportedException (); } + } + + public override IMetadataScope Scope { + get { return element_type.Scope; } + } + + public override ModuleDefinition Module { + get { return element_type.Module; } + } + + public override string FullName { + get { return element_type.FullName; } + } + + internal override bool ContainsGenericParameter { + get { return element_type.ContainsGenericParameter; } + } + + public override MetadataType MetadataType { + get { return (MetadataType) etype; } + } + + internal TypeSpecification (TypeReference type) + : base (null, null) + { + this.element_type = type; + this.token = new MetadataToken (TokenType.TypeSpec); + } + + public override TypeReference GetElementType () + { + return element_type.GetElementType (); + } + } + + static partial class Mixin { + + public static void CheckType (TypeReference type) + { + if (type == null) + throw new ArgumentNullException ("type"); + } + } +} diff --git a/Mono.Cecil/TypeSystem.cs b/Mono.Cecil/TypeSystem.cs new file mode 100644 index 000000000..0b0ba91b9 --- /dev/null +++ b/Mono.Cecil/TypeSystem.cs @@ -0,0 +1,273 @@ +// +// TypeSystem.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +using Mono.Cecil.Metadata; + +namespace Mono.Cecil { + + public abstract class TypeSystem { + + sealed class CorlibTypeSystem : TypeSystem { + + public CorlibTypeSystem (ModuleDefinition module) + : base (module) + { + } + + internal override TypeReference LookupType (string @namespace, string name) + { + var metadata = module.MetadataSystem; + if (metadata.Types == null) + Initialize (module.Types); + + return module.Read (this, (_, reader) => { + var types = reader.metadata.Types; + + for (int i = 0; i < types.Length; i++) { + if (types [i] == null) + types [i] = reader.GetTypeDefinition ((uint) i + 1); + + var type = types [i]; + + if (type.Name == name && type.Namespace == @namespace) + return type; + } + + return null; + }); + } + + static void Initialize (object obj) + { + } + } + + sealed class CommonTypeSystem : TypeSystem { + + AssemblyNameReference corlib; + + public CommonTypeSystem (ModuleDefinition module) + : base (module) + { + } + + internal override TypeReference LookupType (string @namespace, string name) + { + return CreateTypeReference (@namespace, name); + } + + public AssemblyNameReference GetCorlibReference () + { + if (corlib != null) + return corlib; + + const string mscorlib = "mscorlib"; + + var references = module.AssemblyReferences; + + for (int i = 0; i < references.Count; i++) { + var reference = references [i]; + if (reference.Name == mscorlib) + return corlib = reference; + } + + corlib = new AssemblyNameReference { + Name = mscorlib, + Version = GetCorlibVersion (), + PublicKeyToken = new byte [] { 0xb7, 0x7a, 0x5c, 0x56, 0x19, 0x34, 0xe0, 0x89 }, + }; + + references.Add (corlib); + + return corlib; + } + + Version GetCorlibVersion () + { + switch (module.Runtime) { + case TargetRuntime.Net_1_0: + case TargetRuntime.Net_1_1: + return new Version (1, 0, 0, 0); + case TargetRuntime.Net_2_0: + return new Version (2, 0, 0, 0); + case TargetRuntime.Net_4_0: + return new Version (4, 0, 0, 0); + default: + throw new NotSupportedException (); + } + } + + TypeReference CreateTypeReference (string @namespace, string name) + { + return new TypeReference (@namespace, name, module, GetCorlibReference ()); + } + } + + readonly ModuleDefinition module; + + TypeReference type_object; + TypeReference type_void; + TypeReference type_bool; + TypeReference type_char; + TypeReference type_sbyte; + TypeReference type_byte; + TypeReference type_int16; + TypeReference type_uint16; + TypeReference type_int32; + TypeReference type_uint32; + TypeReference type_int64; + TypeReference type_uint64; + TypeReference type_single; + TypeReference type_double; + TypeReference type_intptr; + TypeReference type_uintptr; + TypeReference type_string; + TypeReference type_typedref; + + TypeSystem (ModuleDefinition module) + { + this.module = module; + } + + internal static TypeSystem CreateTypeSystem (ModuleDefinition module) + { + if (IsCorlib (module)) + return new CorlibTypeSystem (module); + + return new CommonTypeSystem (module); + } + + static bool IsCorlib (ModuleDefinition module) + { + if (module.Assembly == null) + return false; + + return module.Assembly.Name.Name == "mscorlib"; + } + + internal abstract TypeReference LookupType (string @namespace, string name); + + TypeReference LookupSystemType (string name, ElementType element_type) + { + var type = LookupType ("System", name); + type.etype = element_type; + return type; + } + + TypeReference LookupSystemValueType (string name, ElementType element_type) + { + var type = LookupSystemType (name, element_type); + type.IsValueType = true; + return type; + } + + public IMetadataScope Corlib { + get { + var common = this as CommonTypeSystem; + if (common == null) + return module; + + return common.GetCorlibReference (); + } + } + + public TypeReference Object { + get { return type_object ?? (type_object = LookupSystemType ("Object", ElementType.Object)); } + } + + public TypeReference Void { + get { return type_void ?? (type_void = LookupSystemType ("Void", ElementType.Void)); } + } + + public TypeReference Boolean { + get { return type_bool ?? (type_bool = LookupSystemValueType ("Boolean", ElementType.Boolean)); } + } + + public TypeReference Char { + get { return type_char ?? (type_char = LookupSystemValueType ("Char", ElementType.Char)); } + } + + public TypeReference SByte { + get { return type_sbyte ?? (type_sbyte = LookupSystemValueType ("SByte", ElementType.I1)); } + } + + public TypeReference Byte { + get { return type_byte ?? (type_byte = LookupSystemValueType ("Byte", ElementType.U1)); } + } + + public TypeReference Int16 { + get { return type_int16 ?? (type_int16 = LookupSystemValueType ("Int16", ElementType.I2)); } + } + + public TypeReference UInt16 { + get { return type_uint16 ?? (type_uint16 = LookupSystemValueType ("UInt16", ElementType.U2)); } + } + + public TypeReference Int32 { + get { return type_int32 ?? (type_int32 = LookupSystemValueType ("Int32", ElementType.I4)); } + } + + public TypeReference UInt32 { + get { return type_uint32 ?? (type_uint32 = LookupSystemValueType ("UInt32", ElementType.U4)); } + } + + public TypeReference Int64 { + get { return type_int64 ?? (type_int64 = LookupSystemValueType ("Int64", ElementType.I8)); } + } + + public TypeReference UInt64 { + get { return type_uint64 ?? (type_uint64 = LookupSystemValueType ("UInt64", ElementType.U8)); } + } + + public TypeReference Single { + get { return type_single ?? (type_single = LookupSystemValueType ("Single", ElementType.R4)); } + } + + public TypeReference Double { + get { return type_double ?? (type_double = LookupSystemValueType ("Double", ElementType.R8)); } + } + + public TypeReference IntPtr { + get { return type_intptr ?? (type_intptr = LookupSystemValueType ("IntPtr", ElementType.I)); } + } + + public TypeReference UIntPtr { + get { return type_uintptr ?? (type_uintptr = LookupSystemValueType ("UIntPtr", ElementType.U)); } + } + + public TypeReference String { + get { return type_string ?? (type_string = LookupSystemType ("String", ElementType.String)); } + } + + public TypeReference TypedReference { + get { return type_typedref ?? (type_typedref = LookupSystemValueType ("TypedReference", ElementType.TypedByRef)); } + } + } +} diff --git a/Mono.Cecil/VariantType.cs b/Mono.Cecil/VariantType.cs new file mode 100644 index 000000000..86d6daaa6 --- /dev/null +++ b/Mono.Cecil/VariantType.cs @@ -0,0 +1,53 @@ +// +// VariantType.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace Mono.Cecil { + + public enum VariantType { + None = 0, + I2 = 2, + I4 = 3, + R4 = 4, + R8 = 5, + CY = 6, + Date = 7, + BStr = 8, + Dispatch = 9, + Error = 10, + Bool = 11, + Variant = 12, + Unknown = 13, + Decimal = 14, + I1 = 16, + UI1 = 17, + UI2 = 18, + UI4 = 19, + Int = 22, + UInt = 23 + } +} diff --git a/Mono.Collections.Generic/Collection.cs b/Mono.Collections.Generic/Collection.cs new file mode 100644 index 000000000..1137978aa --- /dev/null +++ b/Mono.Collections.Generic/Collection.cs @@ -0,0 +1,417 @@ +// +// Collection.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Mono.Collections.Generic { + + public class Collection : IList, IList { + + internal T [] items; + internal int size; + int version; + + public int Count { + get { return size; } + } + + public T this [int index] { + get { + if (index >= size) + throw new ArgumentOutOfRangeException (); + + return items [index]; + } + set { + CheckIndex (index); + if (index == size) + throw new ArgumentOutOfRangeException (); + + OnSet (value, index); + + items [index] = value; + } + } + + bool ICollection.IsReadOnly { + get { return false; } + } + + bool IList.IsFixedSize { + get { return false; } + } + + bool IList.IsReadOnly { + get { return false; } + } + + object IList.this [int index] { + get { return this [index]; } + set { + CheckIndex (index); + + try { + this [index] = (T) value; + return; + } catch (InvalidCastException) { + } catch (NullReferenceException) { + } + + throw new ArgumentException (); + } + } + + int ICollection.Count { + get { return Count; } + } + + bool ICollection.IsSynchronized { + get { return false; } + } + + object ICollection.SyncRoot { + get { return this; } + } + + public Collection () + { + items = Empty.Array; + } + + public Collection (int capacity) + { + if (capacity < 0) + throw new ArgumentOutOfRangeException (); + + items = new T [capacity]; + } + + public Collection (ICollection items) + { + this.items = new T [items.Count]; + items.CopyTo (this.items, 0); + this.size = this.items.Length; + } + + public void Add (T item) + { + if (size == items.Length) + Grow (1); + + OnAdd (item, size); + + items [size++] = item; + version++; + } + + public bool Contains (T item) + { + return IndexOf (item) != -1; + } + + public int IndexOf (T item) + { + return Array.IndexOf (items, item, 0, size); + } + + public void Insert (int index, T item) + { + CheckIndex (index); + if (size == items.Length) + Grow (1); + + OnInsert (item, index); + + Shift (index, 1); + items [index] = item; + version++; + } + + public void RemoveAt (int index) + { + if (index < 0 || index >= size) + throw new ArgumentOutOfRangeException (); + + var item = items [index]; + + OnRemove (item, index); + + Shift (index, -1); + Array.Clear (items, size, 1); + version++; + } + + public bool Remove (T item) + { + var index = IndexOf (item); + if (index == -1) + return false; + + OnRemove (item, index); + + Shift (index, -1); + Array.Clear (items, size, 1); + version++; + + return true; + } + + public void Clear () + { + OnClear (); + + Array.Clear (items, 0, size); + size = 0; + version++; + } + + public void CopyTo (T [] array, int arrayIndex) + { + Array.Copy (items, 0, array, arrayIndex, size); + } + + public T [] ToArray () + { + var array = new T [size]; + Array.Copy (items, 0, array, 0, size); + return array; + } + + void CheckIndex (int index) + { + if (index < 0 || index > size) + throw new ArgumentOutOfRangeException (); + } + + void Shift (int start, int delta) + { + if (delta < 0) + start -= delta; + + if (start < size) + Array.Copy (items, start, items, start + delta, size - start); + + size += delta; + + if (delta < 0) + Array.Clear (items, size, -delta); + } + + protected virtual void OnAdd (T item, int index) + { + } + + protected virtual void OnInsert (T item, int index) + { + } + + protected virtual void OnSet (T item, int index) + { + } + + protected virtual void OnRemove (T item, int index) + { + } + + protected virtual void OnClear () + { + } + + internal virtual void Grow (int desired) + { + int new_size = size + desired; + if (new_size <= items.Length) + return; + + const int default_capacity = 4; + + new_size = System.Math.Max ( + System.Math.Max (items.Length * 2, default_capacity), + new_size); + +#if !CF + Array.Resize (ref items, new_size); +#else + var array = new T [new_size]; + Array.Copy (items, array, size); + items = array; +#endif + } + + int IList.Add (object value) + { + try { + Add ((T) value); + return size - 1; + } catch (InvalidCastException) { + } catch (NullReferenceException) { + } + + throw new ArgumentException (); + } + + void IList.Clear () + { + Clear (); + } + + bool IList.Contains (object value) + { + return ((IList) this).IndexOf (value) > -1; + } + + int IList.IndexOf (object value) + { + try { + return IndexOf ((T) value); + } catch (InvalidCastException) { + } catch (NullReferenceException) { + } + + return -1; + } + + void IList.Insert (int index, object value) + { + CheckIndex (index); + + try { + Insert (index, (T) value); + return; + } catch (InvalidCastException) { + } catch (NullReferenceException) { + } + + throw new ArgumentException (); + } + + void IList.Remove (object value) + { + try { + Remove ((T) value); + } catch (InvalidCastException) { + } catch (NullReferenceException) { + } + } + + void IList.RemoveAt (int index) + { + RemoveAt (index); + } + + void ICollection.CopyTo (Array array, int index) + { + Array.Copy (items, 0, array, index, size); + } + + public Enumerator GetEnumerator () + { + return new Enumerator (this); + } + + IEnumerator IEnumerable.GetEnumerator () + { + return new Enumerator (this); + } + + IEnumerator IEnumerable.GetEnumerator () + { + return new Enumerator (this); + } + + public struct Enumerator : IEnumerator, IDisposable { + + Collection collection; + T current; + + int next; + readonly int version; + + public T Current { + get { return current; } + } + + object IEnumerator.Current { + get { + CheckState (); + + if (next <= 0) + throw new InvalidOperationException (); + + return current; + } + } + + internal Enumerator (Collection collection) + : this () + { + this.collection = collection; + this.version = collection.version; + } + + public bool MoveNext () + { + CheckState (); + + if (next < 0) + return false; + + if (next < collection.size) { + current = collection.items [next++]; + return true; + } + + next = -1; + return false; + } + + public void Reset () + { + CheckState (); + + next = 0; + } + + void CheckState () + { + if (collection == null) + throw new ObjectDisposedException (GetType ().FullName); + + if (version != collection.version) + throw new InvalidOperationException (); + } + + public void Dispose () + { + collection = null; + } + } + } +} diff --git a/Mono.Collections.Generic/ReadOnlyCollection.cs b/Mono.Collections.Generic/ReadOnlyCollection.cs new file mode 100644 index 000000000..bd467c9b8 --- /dev/null +++ b/Mono.Collections.Generic/ReadOnlyCollection.cs @@ -0,0 +1,103 @@ +// +// ReadOnlyCollection.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections; +using System .Collections.Generic; + +namespace Mono.Collections.Generic { + + public sealed class ReadOnlyCollection : Collection, ICollection, IList { + + static ReadOnlyCollection empty; + + public static ReadOnlyCollection Empty { + get { return empty ?? (empty = new ReadOnlyCollection ()); } + } + + bool ICollection.IsReadOnly { + get { return true; } + } + + bool IList.IsReadOnly { + get { return true; } + } + + private ReadOnlyCollection () + { + } + + public ReadOnlyCollection (T [] array) + { + if (array == null) + throw new ArgumentNullException (); + + this.items = array; + this.size = array.Length; + } + + public ReadOnlyCollection (Collection collection) + { + if (collection == null) + throw new ArgumentNullException (); + + this.items = collection.items; + this.size = collection.size; + } + + internal override void Grow (int desired) + { + throw new InvalidOperationException (); + } + + protected override void OnAdd (T item, int index) + { + throw new InvalidOperationException (); + } + + protected override void OnClear () + { + throw new InvalidOperationException (); + } + + protected override void OnInsert (T item, int index) + { + throw new InvalidOperationException (); + } + + protected override void OnRemove (T item, int index) + { + throw new InvalidOperationException (); + } + + protected override void OnSet (T item, int index) + { + throw new InvalidOperationException (); + } + } +} diff --git a/Mono.Security.Cryptography/CryptoConvert.cs b/Mono.Security.Cryptography/CryptoConvert.cs new file mode 100644 index 000000000..26a4ba25b --- /dev/null +++ b/Mono.Security.Cryptography/CryptoConvert.cs @@ -0,0 +1,243 @@ +// +// CryptoConvert.cs - Crypto Convertion Routines +// +// Author: +// Sebastien Pouliot +// +// (C) 2003 Motus Technologies Inc. (http://www.motus.com) +// Copyright (C) 2004-2006 Novell Inc. (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Security.Cryptography; + +#if !(SILVERLIGHT || READ_ONLY) + +namespace Mono.Security.Cryptography { + + static class CryptoConvert { + + static private int ToInt32LE (byte [] bytes, int offset) + { + return (bytes [offset+3] << 24) | (bytes [offset+2] << 16) | (bytes [offset+1] << 8) | bytes [offset]; + } + + static private uint ToUInt32LE (byte [] bytes, int offset) + { + return (uint)((bytes [offset+3] << 24) | (bytes [offset+2] << 16) | (bytes [offset+1] << 8) | bytes [offset]); + } + + static private byte[] Trim (byte[] array) + { + for (int i=0; i < array.Length; i++) { + if (array [i] != 0x00) { + byte[] result = new byte [array.Length - i]; + Buffer.BlockCopy (array, i, result, 0, result.Length); + return result; + } + } + return null; + } + + static RSA FromCapiPrivateKeyBlob (byte[] blob, int offset) + { + RSAParameters rsap = new RSAParameters (); + try { + if ((blob [offset] != 0x07) || // PRIVATEKEYBLOB (0x07) + (blob [offset+1] != 0x02) || // Version (0x02) + (blob [offset+2] != 0x00) || // Reserved (word) + (blob [offset+3] != 0x00) || + (ToUInt32LE (blob, offset+8) != 0x32415352)) // DWORD magic = RSA2 + throw new CryptographicException ("Invalid blob header"); + + // ALGID (CALG_RSA_SIGN, CALG_RSA_KEYX, ...) + // int algId = ToInt32LE (blob, offset+4); + + // DWORD bitlen + int bitLen = ToInt32LE (blob, offset+12); + + // DWORD public exponent + byte[] exp = new byte [4]; + Buffer.BlockCopy (blob, offset+16, exp, 0, 4); + Array.Reverse (exp); + rsap.Exponent = Trim (exp); + + int pos = offset+20; + // BYTE modulus[rsapubkey.bitlen/8]; + int byteLen = (bitLen >> 3); + rsap.Modulus = new byte [byteLen]; + Buffer.BlockCopy (blob, pos, rsap.Modulus, 0, byteLen); + Array.Reverse (rsap.Modulus); + pos += byteLen; + + // BYTE prime1[rsapubkey.bitlen/16]; + int byteHalfLen = (byteLen >> 1); + rsap.P = new byte [byteHalfLen]; + Buffer.BlockCopy (blob, pos, rsap.P, 0, byteHalfLen); + Array.Reverse (rsap.P); + pos += byteHalfLen; + + // BYTE prime2[rsapubkey.bitlen/16]; + rsap.Q = new byte [byteHalfLen]; + Buffer.BlockCopy (blob, pos, rsap.Q, 0, byteHalfLen); + Array.Reverse (rsap.Q); + pos += byteHalfLen; + + // BYTE exponent1[rsapubkey.bitlen/16]; + rsap.DP = new byte [byteHalfLen]; + Buffer.BlockCopy (blob, pos, rsap.DP, 0, byteHalfLen); + Array.Reverse (rsap.DP); + pos += byteHalfLen; + + // BYTE exponent2[rsapubkey.bitlen/16]; + rsap.DQ = new byte [byteHalfLen]; + Buffer.BlockCopy (blob, pos, rsap.DQ, 0, byteHalfLen); + Array.Reverse (rsap.DQ); + pos += byteHalfLen; + + // BYTE coefficient[rsapubkey.bitlen/16]; + rsap.InverseQ = new byte [byteHalfLen]; + Buffer.BlockCopy (blob, pos, rsap.InverseQ, 0, byteHalfLen); + Array.Reverse (rsap.InverseQ); + pos += byteHalfLen; + + // ok, this is hackish but CryptoAPI support it so... + // note: only works because CRT is used by default + // http://bugzilla.ximian.com/show_bug.cgi?id=57941 + rsap.D = new byte [byteLen]; // must be allocated + if (pos + byteLen + offset <= blob.Length) { + // BYTE privateExponent[rsapubkey.bitlen/8]; + Buffer.BlockCopy (blob, pos, rsap.D, 0, byteLen); + Array.Reverse (rsap.D); + } + } + catch (Exception e) { + throw new CryptographicException ("Invalid blob.", e); + } + + RSA rsa = null; + try { + rsa = RSA.Create (); + rsa.ImportParameters (rsap); + } + catch (CryptographicException ce) { + // this may cause problem when this code is run under + // the SYSTEM identity on Windows (e.g. ASP.NET). See + // http://bugzilla.ximian.com/show_bug.cgi?id=77559 + try { + CspParameters csp = new CspParameters (); + csp.Flags = CspProviderFlags.UseMachineKeyStore; + rsa = new RSACryptoServiceProvider (csp); + rsa.ImportParameters (rsap); + } + catch { + // rethrow original, not the later, exception if this fails + throw ce; + } + } + return rsa; + } + + static RSA FromCapiPublicKeyBlob (byte[] blob, int offset) + { + try { + if ((blob [offset] != 0x06) || // PUBLICKEYBLOB (0x06) + (blob [offset+1] != 0x02) || // Version (0x02) + (blob [offset+2] != 0x00) || // Reserved (word) + (blob [offset+3] != 0x00) || + (ToUInt32LE (blob, offset+8) != 0x31415352)) // DWORD magic = RSA1 + throw new CryptographicException ("Invalid blob header"); + + // ALGID (CALG_RSA_SIGN, CALG_RSA_KEYX, ...) + // int algId = ToInt32LE (blob, offset+4); + + // DWORD bitlen + int bitLen = ToInt32LE (blob, offset+12); + + // DWORD public exponent + RSAParameters rsap = new RSAParameters (); + rsap.Exponent = new byte [3]; + rsap.Exponent [0] = blob [offset+18]; + rsap.Exponent [1] = blob [offset+17]; + rsap.Exponent [2] = blob [offset+16]; + + int pos = offset+20; + // BYTE modulus[rsapubkey.bitlen/8]; + int byteLen = (bitLen >> 3); + rsap.Modulus = new byte [byteLen]; + Buffer.BlockCopy (blob, pos, rsap.Modulus, 0, byteLen); + Array.Reverse (rsap.Modulus); + + RSA rsa = null; + try { + rsa = RSA.Create (); + rsa.ImportParameters (rsap); + } + catch (CryptographicException) { + // this may cause problem when this code is run under + // the SYSTEM identity on Windows (e.g. ASP.NET). See + // http://bugzilla.ximian.com/show_bug.cgi?id=77559 + CspParameters csp = new CspParameters (); + csp.Flags = CspProviderFlags.UseMachineKeyStore; + rsa = new RSACryptoServiceProvider (csp); + rsa.ImportParameters (rsap); + } + return rsa; + } + catch (Exception e) { + throw new CryptographicException ("Invalid blob.", e); + } + } + + // PRIVATEKEYBLOB + // PUBLICKEYBLOB + static public RSA FromCapiKeyBlob (byte[] blob) + { + return FromCapiKeyBlob (blob, 0); + } + + static public RSA FromCapiKeyBlob (byte[] blob, int offset) + { + if (blob == null) + throw new ArgumentNullException ("blob"); + if (offset >= blob.Length) + throw new ArgumentException ("blob is too small."); + + switch (blob [offset]) { + case 0x00: + // this could be a public key inside an header + // like "sn -e" would produce + if (blob [offset + 12] == 0x06) { + return FromCapiPublicKeyBlob (blob, offset + 12); + } + break; + case 0x06: + return FromCapiPublicKeyBlob (blob, offset); + case 0x07: + return FromCapiPrivateKeyBlob (blob, offset); + } + throw new CryptographicException ("Unknown blob format."); + } + } +} + +#endif diff --git a/Mono.Security.Cryptography/CryptoService.cs b/Mono.Security.Cryptography/CryptoService.cs new file mode 100644 index 000000000..f504f5eb6 --- /dev/null +++ b/Mono.Security.Cryptography/CryptoService.cs @@ -0,0 +1,177 @@ +// +// CryptoService.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.IO; +using System.Reflection; +using System.Security.Cryptography; + +#if !READ_ONLY + +#if !SILVERLIGHT && !CF +using System.Runtime.Serialization; +using Mono.Security.Cryptography; +#endif + +using Mono.Cecil.PE; + +namespace Mono.Cecil { + + // Most of this code has been adapted + // from Jeroen Frijters' fantastic work + // in IKVM.Reflection.Emit. Thanks! + + static class CryptoService { + +#if !SILVERLIGHT && !CF + public static void StrongName (Stream stream, ImageWriter writer, StrongNameKeyPair key_pair) + { + int strong_name_pointer; + + var strong_name = CreateStrongName (key_pair, HashStream (stream, writer, out strong_name_pointer)); + PatchStrongName (stream, strong_name_pointer, strong_name); + } + + static void PatchStrongName (Stream stream, int strong_name_pointer, byte [] strong_name) + { + stream.Seek (strong_name_pointer, SeekOrigin.Begin); + stream.Write (strong_name, 0, strong_name.Length); + } + + static byte [] CreateStrongName (StrongNameKeyPair key_pair, byte [] hash) + { + const string hash_algo = "SHA1"; + + using (var rsa = key_pair.CreateRSA ()) { + var formatter = new RSAPKCS1SignatureFormatter (rsa); + formatter.SetHashAlgorithm (hash_algo); + + byte [] signature = formatter.CreateSignature (hash); + Array.Reverse (signature); + + return signature; + } + } + + static byte [] HashStream (Stream stream, ImageWriter writer, out int strong_name_pointer) + { + const int buffer_size = 8192; + + var text = writer.text; + var header_size = (int) writer.GetHeaderSize (); + var text_section_pointer = (int) text.PointerToRawData; + var strong_name_directory = writer.GetStrongNameSignatureDirectory (); + + if (strong_name_directory.Size == 0) + throw new InvalidOperationException (); + + strong_name_pointer = (int) (text_section_pointer + + (strong_name_directory.VirtualAddress - text.VirtualAddress)); + var strong_name_length = (int) strong_name_directory.Size; + + var sha1 = new SHA1Managed (); + var buffer = new byte [buffer_size]; + using (var crypto_stream = new CryptoStream (Stream.Null, sha1, CryptoStreamMode.Write)) { + + stream.Seek (0, SeekOrigin.Begin); + CopyStreamChunk (stream, crypto_stream, buffer, header_size); + + stream.Seek (text_section_pointer, SeekOrigin.Begin); + CopyStreamChunk (stream, crypto_stream, buffer, (int) strong_name_pointer - text_section_pointer); + + stream.Seek (strong_name_length, SeekOrigin.Current); + CopyStreamChunk (stream, crypto_stream, buffer, (int) (stream.Length - (strong_name_pointer + strong_name_length))); + } + + return sha1.Hash; + } +#endif + static void CopyStreamChunk (Stream stream, Stream dest_stream, byte [] buffer, int length) + { + while (length > 0) { + int read = stream.Read (buffer, 0, System.Math.Min (buffer.Length, length)); + dest_stream.Write (buffer, 0, read); + length -= read; + } + } + + public static byte [] ComputeHash (string file) + { + if (!File.Exists (file)) + return Empty.Array; + + const int buffer_size = 8192; + + var sha1 = new SHA1Managed (); + + using (var stream = new FileStream (file, FileMode.Open, FileAccess.Read, FileShare.Read)) { + + var buffer = new byte [buffer_size]; + + using (var crypto_stream = new CryptoStream (Stream.Null, sha1, CryptoStreamMode.Write)) + CopyStreamChunk (stream, crypto_stream, buffer, (int) stream.Length); + } + + return sha1.Hash; + } + } + +#if !SILVERLIGHT && !CF + static partial class Mixin { + + public static RSA CreateRSA (this StrongNameKeyPair key_pair) + { + byte [] key; + string key_container; + + if (!TryGetKeyContainer (key_pair, out key, out key_container)) + return CryptoConvert.FromCapiKeyBlob (key); + + var parameters = new CspParameters { + Flags = CspProviderFlags.UseMachineKeyStore, + KeyContainerName = key_container, + KeyNumber = 2, + }; + + return new RSACryptoServiceProvider (parameters); + } + + static bool TryGetKeyContainer (ISerializable key_pair, out byte [] key, out string key_container) + { + var info = new SerializationInfo (typeof (StrongNameKeyPair), new FormatterConverter ()); + key_pair.GetObjectData (info, new StreamingContext ()); + + key = (byte []) info.GetValue ("_keyPairArray", typeof (byte [])); + key_container = info.GetString ("_keyPairContainer"); + return key_container != null; + } + } +#endif +} + +#endif diff --git a/Mono/Actions.cs b/Mono/Actions.cs new file mode 100644 index 000000000..071b14988 --- /dev/null +++ b/Mono/Actions.cs @@ -0,0 +1,38 @@ +// +// Actions.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +#if !NET_3_5 && !NET_4_0 + +namespace Mono { + //delegate void Action (); + //delegate void Action (T1 arg1, T2 arg2); + //delegate void Action (T1 arg1, T2 arg2, T3 arg3); + //delegate void Action (T1 arg1, T2 arg2, T3 arg3, T4 arg4); +} + +#endif diff --git a/Mono/Empty.cs b/Mono/Empty.cs new file mode 100644 index 000000000..70739af58 --- /dev/null +++ b/Mono/Empty.cs @@ -0,0 +1,55 @@ +// +// Empty.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Mono { + + static class Empty { + + public static readonly T [] Array = new T [0]; + } +} + +namespace Mono.Cecil { + + static partial class Mixin { + + public static bool IsNullOrEmpty (this T [] self) + { + return self == null || self.Length == 0; + } + + public static bool IsNullOrEmpty (this ICollection self) + { + return self == null || self.Count == 0; + } + } +} diff --git a/Mono/Funcs.cs b/Mono/Funcs.cs new file mode 100644 index 000000000..40f222595 --- /dev/null +++ b/Mono/Funcs.cs @@ -0,0 +1,39 @@ +// +// Funcs.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +#if !NET_3_5 && !NET_4_0 + +namespace Mono { + delegate TResult Func (); + delegate TResult Func (T arg1); + delegate TResult Func (T1 arg1, T2 arg2); + //delegate TResult Func (T1 arg1, T2 arg2, T3 arg3); + //delegate TResult Func (T1 arg1, T2 arg2, T3 arg3, T4 arg4); +} + +#endif diff --git a/NOTES.txt b/NOTES.txt new file mode 100644 index 000000000..6f3618bcc --- /dev/null +++ b/NOTES.txt @@ -0,0 +1,189 @@ +namespaces: + + Mono.Cecil.Binary: deleted, + Mono.Cecil.Metadata: metadata table/rows: deleted. + +collections: + + * Cecil now only exposes Collection of T as a public collection API. + +types: + +Mono.Cecil + + - AssemblyFactory: + Use static Read methods on ModuleDefinition and AssemblyDefinition + to get them. + + + ReadingMode: + specifies if the assembly is either loaded in a deffered + or immediate fashion. + + + ReaderParameters + + ReadingMode + + ISymbolReaderProvider + + + WriterParameters + + ISymbolWriterProvider + + * AssemblyDefinition: + + * Runtime, Kind: moved to ModuleDefiniton + + * ModuleDefinition: + + properties: + + - Image + - MemberReferences + - TypeReferences + - ExternTypes + + * Main -> IsMain. (set removed) : bool + + FullyQualifiedName : string + + Kind : ModuleKind + + Runtime : TargetRuntime + + Architecture : TargetArchitecture + + Attributes : ModuleAttributes + + HasSymbols : bool + + HasExportedTypes : bool + + ExportedTypes : ExportedTypeCollection + + * Types: doesn't contain NestedTypes anymore. + + - AssemblyKind: + renamed to ModuleKind. + + + ModuleKind: + + NetModule + + + TargetArchitecture: + + I386 + + AMD64 + + IA64 + + + ModuleAttributes: + + ILOnly + + Required32Bit + + StrongNameSigned + + * FieldDefinition: + + * RVA : int + + * IMethodSignature: + * ReturnType : TypeReference + + MethodReturnType : MethodReturnType + + * TypeDefinition: + - HasConstructors + - Constructors + * ctor: swapped namespace and name parameter. + + * ParameterDefinition: + * Method : IMethodSignature + * Sequence -> Index : int (0 based instead of 1) + + * ArrayType: + * IsSizedArray -> IsVector : bool + + * IHasConstant -> IConstantProvider + * IHasSecurity -> ISecurityDeclarationProvider + * IHasMarshal -> IMarshalInfoProvider + + * MemberReference + + Module : ModuleDefinition + + * MethodDefinition: + - This: moved to MethodBody + + HasPInvokeInfo : bool + + * PInvokeInfo: + - Method + + * MarshalSpec -> MarshalInfo + + - ModType + + * ModifierRequiredType -> RequiredModifierType + * ModifierOptionalType -> OptionalModifierType + * ReferenceType -> ByReferenceType + + * TypeReference + + IsArray : bool + + IsPointer : bool + + IsByReference : bool + + IsRequiredModifier : bool + + IsOptionalModifier : bool + + IsSentinel : bool + + IsGenericInstance : bool + + IsGenericParameter : bool + + IsPinned : bool + + IsFunctionPointer : bool + + IsDefinition : bool + + * GetOriginalType -> GetElementType + * ctor: swapped namespace and name parameter. + + * MethodReference + + IsGenericInstance : bool + + IsDefinition : bool + + * GetOriginalMethod -> GetElementMethod + + * FieldReference + + IsDefinition : bool + + + CustomAttributeArgument + + Type : TypeReference + + Value : object + + * CustomAttribute + * ConstructorParameters -> ConstructorArguments : CustomAttributeArgumentCollection + * Properties : CustomAttributeNamedArgumentCollection + * Fields : CustomAttributeNamedArgumentCollection + + * SecurityDeclaration + - PermissionSet + + SecurityAttributes : SecurityAttributeCollection + + + SecurityAttribute + + AttributeType : TypeReference + + Fields : CustomAttributeNamedArgumentCollection + + Properties : CustomAttributeNamedArgumentCollection + + * IMetadataScope + + MetadataScopeType + + + MetadataScopeType + + AssemblyNameReference + + ModuleDefinition + + ModuleReference + +Mono.Cecil.Cil: + + * ExceptionHandler + * Type -> HandlerType : TypeReference + + * VariableDefinition + - Method + + * Document* : from Guid to enums, the reader/writers are responsible for assigning them. + + * MethodBody + * LocalVarToken : MetadataToken + * MaxStack -> MaxStackSize : int + + ThisParameter: from MethodDefinition + + * OperandType + * ShortInlineParam : ShortInlineArg + * InlineParam : InlineArg + + * CilWorker -> ILProcessor + +TODO: + + * Mono.Cecil.Rocks + * ILGenerator + + * HOWTOs diff --git a/System.Runtime.CompilerServices/ExtensionAttribute.cs b/System.Runtime.CompilerServices/ExtensionAttribute.cs new file mode 100644 index 000000000..ae79cda72 --- /dev/null +++ b/System.Runtime.CompilerServices/ExtensionAttribute.cs @@ -0,0 +1,40 @@ +// +// ExtensionAttribute.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +#if !NET_3_5 && !NET_4_0 + +namespace System.Runtime.CompilerServices { + + [AttributeUsage (AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Assembly)] + sealed class ExtensionAttribute : Attribute { + } +} + +#endif diff --git a/Test/.gitignore b/Test/.gitignore new file mode 100644 index 000000000..5c45d5f9a --- /dev/null +++ b/Test/.gitignore @@ -0,0 +1,7 @@ +bin +obj +*.suo +*.user +*.xml +*.pidb +*.userprefs diff --git a/Test/Mono.Cecil.Tests.csproj b/Test/Mono.Cecil.Tests.csproj new file mode 100644 index 000000000..2bcc896d8 --- /dev/null +++ b/Test/Mono.Cecil.Tests.csproj @@ -0,0 +1,171 @@ + + + + net_4_0_Debug + AnyCPU + 9.0.30729 + 2.0 + {A47B1F49-A81A-43E8-BE6B-DD28AF2C4055} + Library + Properties + Mono.Cecil.Tests + Mono.Cecil.Tests + 512 + true + ..\mono.snk + + + true + full + false + bin\net_2_0_Debug\ + DEBUG;TRACE + prompt + 4 + v2.0 + + + pdbonly + true + bin\net_2_0_Release\ + TRACE + prompt + 4 + v2.0 + + + true + full + false + bin\net_3_5_Debug\ + DEBUG;TRACE;NET_3_5 + prompt + 4 + v3.5 + + + pdbonly + true + bin\net_3_5_Release\ + TRACE;NET_3_5 + prompt + 4 + v3.5 + + + true + full + false + bin\net_4_0_Debug\ + DEBUG;TRACE;NET_3_5;NET_4_0 + prompt + 4 + v4.0 + + + pdbonly + true + bin\net_4_0_Release\ + TRACE;NET_3_5;NET_4_0 + prompt + 4 + v4.0 + + + + + + + False + libs\nunit-2.4.8\nunit.core.dll + + + False + libs\nunit-2.4.8\nunit.core.interfaces.dll + + + False + libs\nunit-2.4.8\nunit.framework.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {D68133BD-1E63-496E-9EDE-4FBDBF77B486} + Mono.Cecil + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Test/Mono.Cecil.Tests/Addin.cs b/Test/Mono.Cecil.Tests/Addin.cs new file mode 100644 index 000000000..b8ede12a5 --- /dev/null +++ b/Test/Mono.Cecil.Tests/Addin.cs @@ -0,0 +1,303 @@ +using System; +using System.IO; +using System.Reflection; + +using NUnit.Core; +using NUnit.Core.Extensibility; + +using Mono.Cecil.Cil; + +namespace Mono.Cecil.Tests { + + public abstract class TestCecilAttribute : Attribute { + + bool verify = true; + Type symbol_reader_provider; + Type symbol_writer_provider; + + public bool Verify { + get { return verify; } + set { verify = value; } + } + + public Type SymbolReaderProvider { + get { return symbol_reader_provider; } + set { symbol_reader_provider = value; } + } + + public Type SymbolWriterProvider { + get { return symbol_writer_provider; } + set { symbol_writer_provider = value; } + } + + public abstract string GetModuleLocation (Assembly assembly); + } + + [AttributeUsage (AttributeTargets.Method, AllowMultiple = false)] + public sealed class TestModuleAttribute : TestCecilAttribute { + + readonly string module; + + public string Module { + get { return module; } + } + + public TestModuleAttribute (string assembly) + { + this.module = assembly; + } + + public override string GetModuleLocation (Assembly assembly) + { + return BaseTestFixture.GetAssemblyResourcePath (module, assembly); + } + } + + [AttributeUsage (AttributeTargets.Method, AllowMultiple = false)] + public sealed class TestCSharpAttribute : TestCecilAttribute { + + readonly string file; + + public string File { + get { return file; } + } + + public TestCSharpAttribute (string file) + { + this.file = file; + } + + public override string GetModuleLocation (Assembly assembly) + { + return CompilationService.CompileResource ( + BaseTestFixture.GetCSharpResourcePath (file, assembly)); + } + } + + [AttributeUsage (AttributeTargets.Method, AllowMultiple = false)] + public sealed class TestILAttribute : TestCecilAttribute { + + readonly string file; + + public string File { + get { return file; } + } + + public TestILAttribute (string file) + { + this.file = file; + } + + public override string GetModuleLocation (Assembly assembly) + { + return CompilationService.CompileResource ( + BaseTestFixture.GetILResourcePath (file, assembly)); + } + } + + class CecilTestCase : NUnitTestMethod { + + readonly TestCecilAttribute attribute; + readonly TestCaseType type; + + public CecilTestCase (MethodInfo method, TestCecilAttribute attribute, TestCaseType type) + : base (method) + { + this.TestName.Name = type.ToString (); + this.TestName.FullName = method.DeclaringType.FullName + "." + method.Name + "." + type; + this.attribute = attribute; + this.type = type; + } + + ModuleDefinition GetModule () + { + var location = attribute.GetModuleLocation (this.Method.DeclaringType.Assembly); + + var parameters = new ReaderParameters { + SymbolReaderProvider = GetSymbolReaderProvider (attribute), + }; + + switch (type) { + case TestCaseType.ReadImmediate: + parameters.ReadingMode = ReadingMode.Immediate; + return ModuleDefinition.ReadModule (location, parameters); + case TestCaseType.ReadDeferred: + parameters.ReadingMode = ReadingMode.Deferred; + return ModuleDefinition.ReadModule (location, parameters); + case TestCaseType.WriteFromImmediate: + parameters.ReadingMode = ReadingMode.Immediate; + return RoundTrip (location, parameters, "cecil-irt"); + case TestCaseType.WriteFromDeferred: + parameters.ReadingMode = ReadingMode.Deferred; + return RoundTrip (location, parameters, "cecil-drt"); + default: + return null; + } + } + + static ISymbolReaderProvider GetSymbolReaderProvider (TestCecilAttribute attribute) + { + if (attribute.SymbolReaderProvider == null) + return null; + + return (ISymbolReaderProvider) Activator.CreateInstance (attribute.SymbolReaderProvider); + } + + static ISymbolWriterProvider GetSymbolWriterProvider (TestCecilAttribute attribute) + { + if (attribute.SymbolReaderProvider == null) + return null; + + return (ISymbolWriterProvider) Activator.CreateInstance (attribute.SymbolWriterProvider); + } + + ModuleDefinition RoundTrip (string location, ReaderParameters reader_parameters, string folder) + { + var module = ModuleDefinition.ReadModule (location, reader_parameters); + var rt_folder = Path.Combine (Path.GetTempPath (), folder); + if (!Directory.Exists (rt_folder)) + Directory.CreateDirectory (rt_folder); + var rt_module = Path.Combine (rt_folder, Path.GetFileName (location)); + + var writer_parameters = new WriterParameters { + SymbolWriterProvider = GetSymbolWriterProvider (attribute), + }; + + Reflect.InvokeMethod (Method, Fixture, new object [] { module }); + + module.Write (rt_module, writer_parameters); + + if (attribute.Verify) + CompilationService.Verify (rt_module); + + return ModuleDefinition.ReadModule (rt_module, reader_parameters); + } + + public override void RunTestMethod (TestCaseResult testResult) + { + var module = GetModule (); + if (module == null) + return; + + Reflect.InvokeMethod (Method, Fixture, new object [] { module }); + + testResult.Success (); + } + } + + class CecilTestSuite : TestSuite { + + public CecilTestSuite (MethodInfo method) + : base (method.DeclaringType.FullName, method.Name) + { + } + + public override TestResult Run (EventListener listener, ITestFilter filter) + { + if (this.Parent != null) + this.Fixture = this.Parent.Fixture; + + return base.Run (listener, filter); + } + + protected override void DoOneTimeSetUp (TestResult suiteResult) + { + } + + protected override void DoOneTimeTearDown (TestResult suiteResult) + { + } + } + + enum TestCaseType { + ReadImmediate, + ReadDeferred, + WriteFromImmediate, + WriteFromDeferred, + } + + static class CecilTestFactory { + + public static CecilTestSuite CreateTestSuite (MethodInfo method) + { + if (method == null) + throw new ArgumentNullException ("method"); + + var suite = new CecilTestSuite (method); + + NUnitFramework.ApplyCommonAttributes (method, suite); + PopulateTestSuite (method, suite); + + return suite; + } + + static void PopulateTestSuite (MethodInfo method, CecilTestSuite suite) + { + var attribute = GetTestCecilAttribute (method); + if (attribute == null) + throw new ArgumentException (); + + foreach (var value in Enum.GetValues (typeof (TestCaseType))) { + var test = CreateTestCase (method, attribute, (TestCaseType) value); + if (test != null) + suite.Add (test); + } + } + + static CecilTestCase CreateTestCase (MethodInfo method, TestCecilAttribute attribute, TestCaseType type) + { + return new CecilTestCase (method, attribute, type); + } + + static TestCecilAttribute GetTestCecilAttribute (MethodInfo method) + { + foreach (var attribute in method.GetCustomAttributes (false)) { + var test = attribute as TestCecilAttribute; + if (test != null) + return test; + } + + return null; + } + } + + [NUnitAddin] + public class CecilTestAddin : IAddin, ITestCaseBuilder { + + public bool Install (IExtensionHost host) + { + if (host == null) + throw new ArgumentNullException ("host"); + + var builders = host.GetExtensionPoint ("TestCaseBuilders"); + if (builders == null) + return false; + + builders.Install (this); + return true; + } + + public Test BuildFrom (MethodInfo method) + { + if (method == null) + throw new ArgumentNullException ("method"); + + return CecilTestFactory.CreateTestSuite (method); + } + + public bool CanBuildFrom (MethodInfo method) + { + if (method == null) + return false; + + return IsCecilTestMethod (method); + } + + static bool IsCecilTestMethod (MethodInfo method) + { + return Reflect.HasAttribute (method, typeof (TestModuleAttribute).FullName, false) + || Reflect.HasAttribute (method, typeof (TestILAttribute).FullName, false) + || Reflect.HasAttribute (method, typeof (TestCSharpAttribute).FullName, false); + } + } +} diff --git a/Test/Mono.Cecil.Tests/AssemblyInfo.cs b/Test/Mono.Cecil.Tests/AssemblyInfo.cs new file mode 100644 index 000000000..07d2e0bf0 --- /dev/null +++ b/Test/Mono.Cecil.Tests/AssemblyInfo.cs @@ -0,0 +1,14 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle ("Mono.Cecil.Tests")] +[assembly: AssemblyProduct ("Mono.Cecil")] +[assembly: AssemblyCopyright ("Copyright © 2008 - 2010 Jb Evain")] + +[assembly: ComVisible (false)] + +[assembly: Guid ("da96c202-696a-457e-89af-5fa74e6bda0d")] + +[assembly: AssemblyVersion ("1.0.0.0")] +[assembly: AssemblyFileVersion ("1.0.0.0")] diff --git a/Test/Mono.Cecil.Tests/AssemblyTests.cs b/Test/Mono.Cecil.Tests/AssemblyTests.cs new file mode 100644 index 000000000..8cd6898fc --- /dev/null +++ b/Test/Mono.Cecil.Tests/AssemblyTests.cs @@ -0,0 +1,25 @@ +using System; + +using Mono.Cecil; + +using NUnit.Framework; + +namespace Mono.Cecil.Tests { + + [TestFixture] + public class AssemblyTests : BaseTestFixture { + + [TestModule ("hello.exe")] + public void Name (ModuleDefinition module) + { + var name = module.Assembly.Name; + + Assert.IsNotNull (name); + + Assert.AreEqual ("hello", name.Name); + Assert.AreEqual (string.Empty, name.Culture); + Assert.AreEqual (new Version (0, 0, 0, 0), name.Version); + Assert.AreEqual (AssemblyHashAlgorithm.SHA1, name.HashAlgorithm); + } + } +} diff --git a/Test/Mono.Cecil.Tests/BaseTestFixture.cs b/Test/Mono.Cecil.Tests/BaseTestFixture.cs new file mode 100644 index 000000000..e160f48af --- /dev/null +++ b/Test/Mono.Cecil.Tests/BaseTestFixture.cs @@ -0,0 +1,76 @@ +using System; +using System.IO; +using System.Reflection; + +using NUnit.Framework; + +using Mono.Cecil.PE; + +namespace Mono.Cecil.Tests { + + public abstract class BaseTestFixture { + + public static string GetResourcePath (string name, Assembly assembly) + { + return Path.Combine (FindResourcesDirectory (assembly), name); + } + + public static string GetAssemblyResourcePath (string name, Assembly assembly) + { + return GetResourcePath (Path.Combine ("assemblies", name), assembly); + } + + public static string GetCSharpResourcePath (string name, Assembly assembly) + { + return GetResourcePath (Path.Combine ("cs", name), assembly); + } + + public static string GetILResourcePath (string name, Assembly assembly) + { + return GetResourcePath (Path.Combine ("il", name), assembly); + } + + public static ModuleDefinition GetResourceModule (string name) + { + return ModuleDefinition.ReadModule (GetAssemblyResourcePath (name, typeof (BaseTestFixture).Assembly)); + } + + public static ModuleDefinition GetResourceModule (string name, ReaderParameters parameters) + { + return ModuleDefinition.ReadModule (GetAssemblyResourcePath (name, typeof (BaseTestFixture).Assembly), parameters); + } + + public static ModuleDefinition GetResourceModule (string name, ReadingMode mode) + { + return ModuleDefinition.ReadModule (GetAssemblyResourcePath (name, typeof (BaseTestFixture).Assembly), new ReaderParameters (mode)); + } + + internal static Image GetResourceImage (string name) + { + using (var fs = new FileStream (GetAssemblyResourcePath (name, typeof (BaseTestFixture).Assembly), FileMode.Open, FileAccess.Read)) + return ImageReader.ReadImageFrom (fs); + } + + public static ModuleDefinition GetCurrentModule () + { + return ModuleDefinition.ReadModule (typeof (BaseTestFixture).Module.FullyQualifiedName); + } + + public static ModuleDefinition GetCurrentModule (ReaderParameters parameters) + { + return ModuleDefinition.ReadModule (typeof (BaseTestFixture).Module.FullyQualifiedName, parameters); + } + + public static string FindResourcesDirectory (Assembly assembly) + { + var path = Path.GetDirectoryName (new Uri (assembly.CodeBase).LocalPath); + while (!Directory.Exists (Path.Combine (path, "Resources"))) { + var old = path; + path = Path.GetDirectoryName (path); + Assert.AreNotEqual (old, path); + } + + return Path.Combine (path, "Resources"); + } + } +} diff --git a/Test/Mono.Cecil.Tests/CompilationService.cs b/Test/Mono.Cecil.Tests/CompilationService.cs new file mode 100644 index 000000000..5a2def5cd --- /dev/null +++ b/Test/Mono.Cecil.Tests/CompilationService.cs @@ -0,0 +1,237 @@ +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; + +using NUnit.Framework; + +namespace Mono.Cecil.Tests { + + struct CompilationResult { + internal DateTime source_write_time; + internal string result_file; + + public CompilationResult (DateTime write_time, string result_file) + { + this.source_write_time = write_time; + this.result_file = result_file; + } + } + + abstract class CompilationService { + + Dictionary files = new Dictionary (); + + bool TryGetResult (string name, out string file_result) + { + file_result = null; + CompilationResult result; + if (!files.TryGetValue (name, out result)) + return false; + + if (result.source_write_time != File.GetLastWriteTime (name)) + return false; + + file_result = result.result_file; + return true; + } + + public string Compile (string name) + { + string result_file; + if (TryGetResult (name, out result_file)) + return result_file; + + result_file = CompileFile (name); + RegisterFile (name, result_file); + return result_file; + } + + void RegisterFile (string name, string result_file) + { + files [name] = new CompilationResult (File.GetLastWriteTime (name), result_file); + } + + protected abstract string CompileFile (string name); + + public static string CompileResource (string name) + { + var extension = Path.GetExtension (name); + if (extension == ".il") + return IlasmCompilationService.Instance.Compile (name); + + if (extension == ".cs" || extension == ".vb") + return CodeDomCompilationService.Instance.Compile (name); + + throw new NotSupportedException (extension); + } + + protected static string GetCompiledFilePath (string file_name) + { + var tmp_cecil = Path.Combine (Path.GetTempPath (), "cecil"); + if (!Directory.Exists (tmp_cecil)) + Directory.CreateDirectory (tmp_cecil); + + return Path.Combine (tmp_cecil, Path.GetFileName (file_name) + ".dll"); + } + + static bool OnMono { get { return typeof (object).Assembly.GetType ("Mono.Runtime") != null; } } + + public static void Verify (string name) + { + var output = OnMono ? ShellService.PEDump (name) : ShellService.PEVerify (name); + if (output.ExitCode != 0) + Assert.Fail (output.ToString ()); + } + } + + class IlasmCompilationService : CompilationService { + + public static readonly IlasmCompilationService Instance = new IlasmCompilationService (); + + protected override string CompileFile (string name) + { + string file = GetCompiledFilePath (name); + + var output = ShellService.ILAsm (name, file); + + AssertAssemblerResult (output); + + return file; + } + + static void AssertAssemblerResult (ShellService.ProcessOutput output) + { + if (output.ExitCode != 0) + Assert.Fail (output.ToString ()); + } + } + + class CodeDomCompilationService : CompilationService { + + public static readonly CodeDomCompilationService Instance = new CodeDomCompilationService (); + + protected override string CompileFile (string name) + { + string file = GetCompiledFilePath (name); + + using (var provider = GetProvider (name)) { + var parameters = GetDefaultParameters (name); + parameters.IncludeDebugInformation = false; + parameters.GenerateExecutable = false; + parameters.OutputAssembly = file; + + var results = provider.CompileAssemblyFromFile (parameters, name); + AssertCompilerResults (results); + } + + return file; + } + + static void AssertCompilerResults (CompilerResults results) + { + Assert.IsFalse (results.Errors.HasErrors, GetErrorMessage (results)); + } + + static string GetErrorMessage (CompilerResults results) + { + if (!results.Errors.HasErrors) + return string.Empty; + + var builder = new StringBuilder (); + foreach (CompilerError error in results.Errors) + builder.AppendLine (error.ToString ()); + return builder.ToString (); + } + + static CompilerParameters GetDefaultParameters (string name) + { + return GetCompilerInfo (name).CreateDefaultCompilerParameters (); + } + + static CodeDomProvider GetProvider (string name) + { + return GetCompilerInfo (name).CreateProvider (); + } + + static CompilerInfo GetCompilerInfo (string name) + { + return CodeDomProvider.GetCompilerInfo ( + CodeDomProvider.GetLanguageFromExtension (Path.GetExtension (name))); + } + } + + class ShellService { + + public class ProcessOutput { + + public int ExitCode; + public string StdOut; + public string StdErr; + + public ProcessOutput (int exitCode, string stdout, string stderr) + { + ExitCode = exitCode; + StdOut = stdout; + StdErr = stderr; + } + + public override string ToString () + { + return StdOut + StdErr; + } + } + + static ProcessOutput RunProcess (string target, params string [] arguments) + { + var stdout = new StringWriter (); + var stderr = new StringWriter (); + + var process = new Process { + StartInfo = new ProcessStartInfo { + FileName = target, + Arguments = string.Join (" ", arguments), + CreateNoWindow = true, + UseShellExecute = false, + RedirectStandardError = true, + RedirectStandardInput = true, + RedirectStandardOutput = true, + }, + }; + + process.Start (); + + process.OutputDataReceived += (_, args) => stdout.Write (args.Data); + process.ErrorDataReceived += (_, args) => stderr.Write (args.Data); + + process.BeginOutputReadLine (); + process.BeginErrorReadLine (); + + process.WaitForExit (); + + return new ProcessOutput (process.ExitCode, stdout.ToString (), stderr.ToString ()); + } + + public static ProcessOutput ILAsm (string source, string output) + { + return RunProcess ("ilasm", "/nologo", "/dll", "/out:" + Quote (output), Quote (source)); + } + + static string Quote (string file) + { + return "\"" + file + "\""; + } + + public static ProcessOutput PEVerify (string source) + { + return RunProcess ("peverify", "/nologo", Quote (source)); + } + + public static ProcessOutput PEDump (string source) + { + return RunProcess ("pedump", "--verify code,metadata", Quote (source)); + } + } +} diff --git a/Test/Mono.Cecil.Tests/CustomAttributesTests.cs b/Test/Mono.Cecil.Tests/CustomAttributesTests.cs new file mode 100644 index 000000000..6565ba6ca --- /dev/null +++ b/Test/Mono.Cecil.Tests/CustomAttributesTests.cs @@ -0,0 +1,511 @@ +using System; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text; + +using Mono.Cecil; +using Mono.Cecil.Metadata; +using Mono.Cecil.PE; + +using NUnit.Framework; + +namespace Mono.Cecil.Tests { + + [TestFixture] + public class CustomAttributesTests : BaseTestFixture { + + [TestCSharp ("CustomAttributes.cs")] + public void StringArgumentOnType (ModuleDefinition module) + { + var hamster = module.GetType ("Hamster"); + + Assert.IsTrue (hamster.HasCustomAttributes); + Assert.AreEqual (1, hamster.CustomAttributes.Count); + + var attribute = hamster.CustomAttributes [0]; + Assert.AreEqual ("System.Void FooAttribute::.ctor(System.String)", + attribute.Constructor.FullName); + + Assert.IsTrue (attribute.HasConstructorArguments); + Assert.AreEqual (1, attribute.ConstructorArguments.Count); + + AssertArgument ("bar", attribute.ConstructorArguments [0]); + } + + [TestCSharp ("CustomAttributes.cs")] + public void NullString (ModuleDefinition module) + { + var dentist = module.GetType ("Dentist"); + + var attribute = GetAttribute (dentist, "Foo"); + Assert.IsNotNull (attribute); + + AssertArgument (null, attribute.ConstructorArguments [0]); + } + + [TestCSharp ("CustomAttributes.cs")] + public void Primitives1 (ModuleDefinition module) + { + var steven = module.GetType ("Steven"); + + var attribute = GetAttribute (steven, "Foo"); + Assert.IsNotNull (attribute); + + AssertArgument (-12, attribute.ConstructorArguments [0]); + AssertArgument (242, attribute.ConstructorArguments [1]); + AssertArgument (true, attribute.ConstructorArguments [2]); + AssertArgument (false, attribute.ConstructorArguments [3]); + AssertArgument (4242, attribute.ConstructorArguments [4]); + AssertArgument (-1983, attribute.ConstructorArguments [5]); + AssertArgument ('c', attribute.ConstructorArguments [6]); + } + + [TestCSharp ("CustomAttributes.cs")] + public void Primitives2 (ModuleDefinition module) + { + var seagull = module.GetType ("Seagull"); + + var attribute = GetAttribute (seagull, "Foo"); + Assert.IsNotNull (attribute); + + AssertArgument (-100000, attribute.ConstructorArguments [0]); + AssertArgument (200000, attribute.ConstructorArguments [1]); + AssertArgument (12.12f, attribute.ConstructorArguments [2]); + AssertArgument (long.MaxValue, attribute.ConstructorArguments [3]); + AssertArgument (ulong.MaxValue, attribute.ConstructorArguments [4]); + AssertArgument (64.646464, attribute.ConstructorArguments [5]); + } + + [TestCSharp ("CustomAttributes.cs")] + public void StringArgumentOnAssembly (ModuleDefinition module) + { + var assembly = module.Assembly; + + var attribute = GetAttribute (assembly, "Foo"); + Assert.IsNotNull (attribute); + + AssertArgument ("bingo", attribute.ConstructorArguments [0]); + } + + [TestCSharp ("CustomAttributes.cs")] + public void CharArray (ModuleDefinition module) + { + var rifle = module.GetType ("Rifle"); + + var attribute = GetAttribute (rifle, "Foo"); + Assert.IsNotNull (attribute); + + var argument = attribute.ConstructorArguments [0]; + + Assert.AreEqual ("System.Char[]", argument.Type.FullName); + + var array = argument.Value as CustomAttributeArgument []; + Assert.IsNotNull (array); + + var str = "cecil"; + + Assert.AreEqual (array.Length, str.Length); + + for (int i = 0; i < str.Length; i++) + AssertArgument (str [i], array [i]); + } + + [TestCSharp ("CustomAttributes.cs")] + public void BoxedArguments (ModuleDefinition module) + { + var worm = module.GetType ("Worm"); + + var attribute = GetAttribute (worm, "Foo"); + Assert.IsNotNull (attribute); + + Assert.AreEqual (".ctor ((Object:(String:\"2\")), (Object:(I4:2)))", PrettyPrint (attribute)); + } + + [TestCSharp ("CustomAttributes.cs")] + public void BoxedArraysArguments (ModuleDefinition module) + { + var sheep = module.GetType ("Sheep"); + + var attribute = GetAttribute (sheep, "Foo"); + Assert.IsNotNull (attribute); + + // [Foo (new object [] { "2", 2, 'c' }, new object [] { new object [] { 1, 2, 3}, null })] + AssertCustomAttribute (".ctor ((Object:(Object[]:{(Object:(String:\"2\")), (Object:(I4:2)), (Object:(Char:'c'))})), (Object:(Object[]:{(Object:(Object[]:{(Object:(I4:1)), (Object:(I4:2)), (Object:(I4:3))})), (Object:(String:null))})))", attribute); + } + + [TestCSharp ("CustomAttributes.cs")] + public void FieldsAndProperties (ModuleDefinition module) + { + var angola = module.GetType ("Angola"); + + var attribute = GetAttribute (angola, "Foo"); + Assert.IsNotNull (attribute); + + Assert.AreEqual (2, attribute.Fields.Count); + + var argument = attribute.Fields.Where (a => a.Name == "Pan").First (); + AssertCustomAttributeArgument ("(Object:(Object[]:{(Object:(I4:1)), (Object:(String:\"2\")), (Object:(Char:'3'))}))", argument); + + argument = attribute.Fields.Where (a => a.Name == "PanPan").First (); + AssertCustomAttributeArgument ("(String[]:{(String:\"yo\"), (String:\"yo\")})", argument); + + Assert.AreEqual (2, attribute.Properties.Count); + + argument = attribute.Properties.Where (a => a.Name == "Bang").First (); + AssertArgument (42, argument); + + argument = attribute.Properties.Where (a => a.Name == "Fiou").First (); + AssertArgument (null, argument); + } + + [TestCSharp ("CustomAttributes.cs")] + public void BoxedStringField (ModuleDefinition module) + { + var type = module.GetType ("BoxedStringField"); + + var attribute = GetAttribute (type, "Foo"); + Assert.IsNotNull (attribute); + + Assert.AreEqual (1, attribute.Fields.Count); + + var argument = attribute.Fields.Where (a => a.Name == "Pan").First (); + AssertCustomAttributeArgument ("(Object:(String:\"fiouuu\"))", argument); + } + + [TestCSharp ("CustomAttributes.cs")] + public void TypeDefinitionEnum (ModuleDefinition module) + { + var zero = module.GetType ("Zero"); + + var attribute = GetAttribute (zero, "Foo"); + Assert.IsNotNull (attribute); + + Assert.AreEqual (1, attribute.ConstructorArguments.Count); + + Assert.AreEqual ((short) 2, attribute.ConstructorArguments [0].Value); + Assert.AreEqual ("Bingo", attribute.ConstructorArguments [0].Type.FullName); + } + + [TestCSharp ("CustomAttributes.cs")] + public void TypeReferenceEnum (ModuleDefinition module) + { + var ace = module.GetType ("Ace"); + + var attribute = GetAttribute (ace, "Foo"); + Assert.IsNotNull (attribute); + + Assert.AreEqual (1, attribute.ConstructorArguments.Count); + + Assert.AreEqual ((byte) 0x04, attribute.ConstructorArguments [0].Value); + Assert.AreEqual ("System.Security.AccessControl.AceFlags", attribute.ConstructorArguments [0].Type.FullName); + Assert.AreEqual (module, attribute.ConstructorArguments [0].Type.Module); + } + + [TestCSharp ("CustomAttributes.cs")] + public void BoxedEnumReference (ModuleDefinition module) + { + var bzzz = module.GetType ("Bzzz"); + + var attribute = GetAttribute (bzzz, "Foo"); + Assert.IsNotNull (attribute); + + // [Foo (new object [] { Bingo.Fuel, Bingo.Binga }, null, Pan = System.Security.AccessControl.AceFlags.NoPropagateInherit)] + + Assert.AreEqual (2, attribute.ConstructorArguments.Count); + + var argument = attribute.ConstructorArguments [0]; + + AssertCustomAttributeArgument ("(Object:(Object[]:{(Object:(Bingo:2)), (Object:(Bingo:4))}))", argument); + + argument = attribute.ConstructorArguments [1]; + + AssertCustomAttributeArgument ("(Object:(String:null))", argument); + + argument = attribute.Fields.Where (a => a.Name == "Pan").First ().Argument; + + AssertCustomAttributeArgument ("(Object:(System.Security.AccessControl.AceFlags:4))", argument); + } + + [TestCSharp ("CustomAttributes.cs")] + public void TypeOfTypeDefinition (ModuleDefinition module) + { + var typed = module.GetType ("Typed"); + + var attribute = GetAttribute (typed, "Foo"); + Assert.IsNotNull (attribute); + + Assert.AreEqual (1, attribute.ConstructorArguments.Count); + + var argument = attribute.ConstructorArguments [0]; + + Assert.AreEqual ("System.Type", argument.Type.FullName); + + var type = argument.Value as TypeDefinition; + Assert.IsNotNull (type); + + Assert.AreEqual ("Bingo", type.FullName); + } + + [TestCSharp ("CustomAttributes.cs")] + public void TypeOfNestedTypeDefinition (ModuleDefinition module) + { + var typed = module.GetType ("NestedTyped"); + + var attribute = GetAttribute (typed, "Foo"); + Assert.IsNotNull (attribute); + + Assert.AreEqual (1, attribute.ConstructorArguments.Count); + + var argument = attribute.ConstructorArguments [0]; + + Assert.AreEqual ("System.Type", argument.Type.FullName); + + var type = argument.Value as TypeDefinition; + Assert.IsNotNull (type); + + Assert.AreEqual ("FooAttribute/Token", type.FullName); + } + + [TestCSharp ("CustomAttributes.cs")] + public void FieldTypeOf (ModuleDefinition module) + { + var truc = module.GetType ("Truc"); + + var attribute = GetAttribute (truc, "Foo"); + Assert.IsNotNull (attribute); + + var argument = attribute.Fields.Where (a => a.Name == "Chose").First ().Argument; + + Assert.AreEqual ("System.Type", argument.Type.FullName); + + var type = argument.Value as TypeDefinition; + Assert.IsNotNull (type); + + Assert.AreEqual ("Typed", type.FullName); + } + + [TestCSharp ("CustomAttributes.cs")] + public void FieldNullTypeOf (ModuleDefinition module) + { + var truc = module.GetType ("Machin"); + + var attribute = GetAttribute (truc, "Foo"); + Assert.IsNotNull (attribute); + + var argument = attribute.Fields.Where (a => a.Name == "Chose").First ().Argument; + + Assert.AreEqual ("System.Type", argument.Type.FullName); + + Assert.IsNull (argument.Value); + } + + [TestCSharp ("CustomAttributes.cs")] + public void OpenGenericTypeOf (ModuleDefinition module) + { + var open_generic = module.GetType ("OpenGeneric`2"); + Assert.IsNotNull (open_generic); + + var attribute = GetAttribute (open_generic, "Foo"); + Assert.IsNotNull (attribute); + + Assert.AreEqual (1, attribute.ConstructorArguments.Count); + + var argument = attribute.ConstructorArguments [0]; + + Assert.AreEqual ("System.Type", argument.Type.FullName); + + var type = argument.Value as TypeReference; + Assert.IsNotNull (type); + + Assert.AreEqual ("System.Collections.Generic.Dictionary`2", type.FullName); + } + + [TestCSharp ("CustomAttributes.cs")] + public void ClosedGenericTypeOf (ModuleDefinition module) + { + var closed_generic = module.GetType ("ClosedGeneric"); + Assert.IsNotNull (closed_generic); + + var attribute = GetAttribute (closed_generic, "Foo"); + Assert.IsNotNull (attribute); + + Assert.AreEqual (1, attribute.ConstructorArguments.Count); + + var argument = attribute.ConstructorArguments [0]; + + Assert.AreEqual ("System.Type", argument.Type.FullName); + + var type = argument.Value as TypeReference; + Assert.IsNotNull (type); + + Assert.AreEqual ("System.Collections.Generic.Dictionary`2[,]>", type.FullName); + } + + [Test] + public void DefineCustomAttributeFromBlob () + { + var file = Path.Combine (Path.GetTempPath (), "CaBlob.dll"); + + var module = ModuleDefinition.CreateModule ("CaBlob.dll", new ModuleParameters { Kind = ModuleKind.Dll, Runtime = TargetRuntime.Net_2_0 }); + var assembly_title_ctor = module.Import (typeof (System.Reflection.AssemblyTitleAttribute).GetConstructor (new [] {typeof (string)})); + + Assert.IsNotNull (assembly_title_ctor); + + var buffer = new ByteBuffer (); + buffer.WriteUInt16 (1); // ca signature + + var title = Encoding.UTF8.GetBytes ("CaBlob"); + + buffer.WriteCompressedUInt32 ((uint) title.Length); + buffer.WriteBytes (title); + + buffer.WriteUInt16 (0); // named arguments + + var blob = new byte [buffer.length]; + Buffer.BlockCopy (buffer.buffer, 0, blob, 0, buffer.length); + + var attribute = new CustomAttribute (assembly_title_ctor, blob); + module.Assembly.CustomAttributes.Add (attribute); + + module.Write (file); + + module = ModuleDefinition.ReadModule (file); + + attribute = GetAttribute (module.Assembly, "AssemblyTitle"); + + Assert.IsNotNull (attribute); + Assert.AreEqual ("CaBlob", (string) attribute.ConstructorArguments [0].Value); + } + + static void AssertCustomAttribute (string expected, CustomAttribute attribute) + { + Assert.AreEqual (expected, PrettyPrint (attribute)); + } + + static void AssertCustomAttributeArgument (string expected, CustomAttributeNamedArgument named_argument) + { + AssertCustomAttributeArgument (expected, named_argument.Argument); + } + + static void AssertCustomAttributeArgument (string expected, CustomAttributeArgument argument) + { + var result = new StringBuilder (); + PrettyPrint (argument, result); + + Assert.AreEqual (expected, result.ToString ()); + } + + static string PrettyPrint (CustomAttribute attribute) + { + var signature = new StringBuilder (); + signature.Append (".ctor ("); + + for (int i = 0; i < attribute.ConstructorArguments.Count; i++) { + if (i > 0) + signature.Append (", "); + + PrettyPrint (attribute.ConstructorArguments [i], signature); + } + + signature.Append (")"); + return signature.ToString (); + } + + static void PrettyPrint (CustomAttributeArgument argument, StringBuilder signature) + { + var value = argument.Value; + + signature.Append ("("); + + PrettyPrint (argument.Type, signature); + + signature.Append (":"); + + PrettyPrintValue (argument.Value, signature); + + signature.Append (")"); + } + + static void PrettyPrintValue (object value, StringBuilder signature) + { + if (value == null) { + signature.Append ("null"); + return; + } + + var arguments = value as CustomAttributeArgument []; + if (arguments != null) { + signature.Append ("{"); + for (int i = 0; i < arguments.Length; i++) { + if (i > 0) + signature.Append (", "); + + PrettyPrint (arguments [i], signature); + } + signature.Append ("}"); + + return; + } + + switch (Type.GetTypeCode (value.GetType ())) { + case TypeCode.String: + signature.AppendFormat ("\"{0}\"", value); + break; + case TypeCode.Char: + signature.AppendFormat ("'{0}'", (char) value); + break; + default: + var formattable = value as IFormattable; + if (formattable != null) { + signature.Append (formattable.ToString (null, CultureInfo.InvariantCulture)); + return; + } + + if (value is CustomAttributeArgument) { + PrettyPrint ((CustomAttributeArgument) value, signature); + return; + } + break; + } + } + + static void PrettyPrint (TypeReference type, StringBuilder signature) + { + if (type.IsArray) { + ArrayType array = (ArrayType) type; + signature.AppendFormat ("{0}[]", array.ElementType.etype.ToString ()); + } else if (type.etype == ElementType.None) { + signature.Append (type.FullName); + } else + signature.Append (type.etype.ToString ()); + } + + static void AssertArgument (T value, CustomAttributeNamedArgument named_argument) + { + AssertArgument (value, named_argument.Argument); + } + + static void AssertArgument (T value, CustomAttributeArgument argument) + { + AssertArgument (typeof (T).FullName, (object) value, argument); + } + + static void AssertArgument (string type, object value, CustomAttributeArgument argument) + { + Assert.AreEqual (type, argument.Type.FullName); + Assert.AreEqual (value, argument.Value); + } + + static CustomAttribute GetAttribute (ICustomAttributeProvider owner, string type) + { + Assert.IsTrue (owner.HasCustomAttributes); + + foreach (var attribute in owner.CustomAttributes) + if (attribute.Constructor.DeclaringType.Name.StartsWith (type)) + return attribute; + + return null; + } + } +} diff --git a/Test/Mono.Cecil.Tests/EventTests.cs b/Test/Mono.Cecil.Tests/EventTests.cs new file mode 100644 index 000000000..15a599c58 --- /dev/null +++ b/Test/Mono.Cecil.Tests/EventTests.cs @@ -0,0 +1,66 @@ +using System; + +using Mono.Cecil; +using Mono.Cecil.Metadata; + +using NUnit.Framework; + +namespace Mono.Cecil.Tests { + + [TestFixture] + public class EventTests : BaseTestFixture { + + [TestCSharp ("Events.cs")] + public void AbstractMethod (ModuleDefinition module) + { + var type = module.GetType ("Foo"); + + Assert.IsTrue (type.HasEvents); + + var events = type.Events; + + Assert.AreEqual (1, events.Count); + + var @event = events [0]; + + Assert.IsNotNull (@event); + Assert.AreEqual ("Bar", @event.Name); + Assert.IsNotNull (@event.EventType); + Assert.AreEqual ("Pan", @event.EventType.FullName); + + Assert.IsNotNull (@event.AddMethod); + Assert.AreEqual (MethodSemanticsAttributes.AddOn, @event.AddMethod.SemanticsAttributes); + Assert.IsNotNull (@event.RemoveMethod); + Assert.AreEqual (MethodSemanticsAttributes.RemoveOn, @event.RemoveMethod.SemanticsAttributes); + } + + [TestIL ("others.il")] + public void OtherMethod (ModuleDefinition module) + { + var type = module.GetType ("Others"); + + Assert.IsTrue (type.HasEvents); + + var events = type.Events; + + Assert.AreEqual (1, events.Count); + + var @event = events [0]; + + Assert.IsNotNull (@event); + Assert.AreEqual ("Handler", @event.Name); + Assert.IsNotNull (@event.EventType); + Assert.AreEqual ("System.EventHandler", @event.EventType.FullName); + + Assert.IsTrue (@event.HasOtherMethods); + + Assert.AreEqual (2, @event.OtherMethods.Count); + + var other = @event.OtherMethods [0]; + Assert.AreEqual ("dang_Handler", other.Name); + + other = @event.OtherMethods [1]; + Assert.AreEqual ("fang_Handler", other.Name); + } + } +} diff --git a/Test/Mono.Cecil.Tests/Extensions.cs b/Test/Mono.Cecil.Tests/Extensions.cs new file mode 100644 index 000000000..0788d21bc --- /dev/null +++ b/Test/Mono.Cecil.Tests/Extensions.cs @@ -0,0 +1,92 @@ +using System; +using System.Linq; +using SR = System.Reflection; + +using Mono.Cecil; + +namespace Mono.Cecil.Tests { + + public static class Extensions { + + public static MethodDefinition GetMethod (this TypeDefinition self, string name) + { + return self.Methods.Where (m => m.Name == name).First (); + } + + public static FieldDefinition GetField (this TypeDefinition self, string name) + { + return self.Fields.Where (f => f.Name == name).First (); + } + + public static TypeDefinition ToDefinition (this Type self) + { + var module = ModuleDefinition.ReadModule (self.Module.FullyQualifiedName); + return (TypeDefinition) module.LookupToken (self.MetadataToken); + } + + public static MethodDefinition ToDefinition (this SR.MethodBase method) + { + var declaring_type = method.DeclaringType.ToDefinition (); + return (MethodDefinition) declaring_type.Module.LookupToken (method.MetadataToken); + } + + public static FieldDefinition ToDefinition (this SR.FieldInfo field) + { + var declaring_type = field.DeclaringType.ToDefinition (); + return (FieldDefinition) declaring_type.Module.LookupToken (field.MetadataToken); + } + + public static TypeReference MakeGenericType (this TypeReference self, params TypeReference [] arguments) + { + if (self.GenericParameters.Count != arguments.Length) + throw new ArgumentException (); + + var instance = new GenericInstanceType (self); + foreach (var argument in arguments) + instance.GenericArguments.Add (argument); + + return instance; + } + + public static MethodReference MakeGenericMethod (this MethodReference self, params TypeReference [] arguments) + { + if (self.GenericParameters.Count != arguments.Length) + throw new ArgumentException (); + + var instance = new GenericInstanceMethod (self); + foreach (var argument in arguments) + instance.GenericArguments.Add (argument); + + return instance; + } + + public static MethodReference MakeGeneric (this MethodReference self, params TypeReference [] arguments) + { + var reference = new MethodReference { + Name = self.Name, + DeclaringType = self.DeclaringType.MakeGenericType (arguments), + HasThis = self.HasThis, + ExplicitThis = self.ExplicitThis, + ReturnType = self.ReturnType, + CallingConvention = self.CallingConvention, + }; + + foreach (var parameter in self.Parameters) + reference.Parameters.Add (new ParameterDefinition (parameter.ParameterType)); + + foreach (var generic_parameter in self.GenericParameters) + reference.GenericParameters.Add (new GenericParameter (generic_parameter.Name, reference)); + + return reference; + } + + public static FieldReference MakeGeneric (this FieldReference self, params TypeReference [] arguments) + { + return new FieldReference { + Name = self.Name, + DeclaringType = self.DeclaringType.MakeGenericType (arguments), + FieldType = self.FieldType, + }; + } + } +} diff --git a/Test/Mono.Cecil.Tests/FieldTests.cs b/Test/Mono.Cecil.Tests/FieldTests.cs new file mode 100644 index 000000000..1927f8569 --- /dev/null +++ b/Test/Mono.Cecil.Tests/FieldTests.cs @@ -0,0 +1,324 @@ +using System; + +using Mono.Cecil; +using Mono.Cecil.Metadata; +using Mono.Cecil.PE; + +using NUnit.Framework; + +namespace Mono.Cecil.Tests { + + [TestFixture] + public class FieldTests : BaseTestFixture { + + [TestCSharp ("Fields.cs")] + public void TypeDefField (ModuleDefinition module) + { + var type = module.Types [1]; + Assert.AreEqual ("Foo", type.Name); + Assert.AreEqual (1, type.Fields.Count); + + var field = type.Fields [0]; + Assert.AreEqual ("bar", field.Name); + Assert.AreEqual (1, field.MetadataToken.RID); + Assert.IsNotNull (field.FieldType); + Assert.AreEqual ("Bar", field.FieldType.FullName); + Assert.AreEqual (TokenType.Field, field.MetadataToken.TokenType); + Assert.IsFalse (field.HasConstant); + Assert.IsNull (field.Constant); + } + + [TestCSharp ("Fields.cs")] + public void PrimitiveTypes (ModuleDefinition module) + { + var type = module.GetType ("Baz"); + + AssertField (type, "char", typeof (char)); + AssertField (type, "bool", typeof (bool)); + AssertField (type, "sbyte", typeof (sbyte)); + AssertField (type, "byte", typeof (byte)); + AssertField (type, "int16", typeof (short)); + AssertField (type, "uint16", typeof (ushort)); + AssertField (type, "int32", typeof (int)); + AssertField (type, "uint32", typeof (uint)); + AssertField (type, "int64", typeof (long)); + AssertField (type, "uint64", typeof (ulong)); + AssertField (type, "single", typeof (float)); + AssertField (type, "double", typeof (double)); + AssertField (type, "string", typeof (string)); + AssertField (type, "object", typeof (object)); + } + + [TestCSharp ("Fields.cs")] + public void VolatileField (ModuleDefinition module) + { + var type = module.GetType ("Bar"); + + Assert.IsTrue (type.HasFields); + Assert.AreEqual (1, type.Fields.Count); + + var field = type.Fields [0]; + + Assert.AreEqual ("oiseau", field.Name); + Assert.AreEqual ("System.Int32 modreq(System.Runtime.CompilerServices.IsVolatile)", field.FieldType.FullName); + + Assert.IsFalse (field.HasConstant); + } + + [TestCSharp ("Layouts.cs")] + public void FieldLayout (ModuleDefinition module) + { + var foo = module.GetType ("Foo"); + Assert.IsNotNull (foo); + + Assert.IsTrue (foo.HasFields); + + var fields = foo.Fields; + + var field = fields [0]; + + Assert.AreEqual ("Bar", field.Name); + Assert.IsTrue (field.HasLayoutInfo); + Assert.AreEqual (0, field.Offset); + + field = fields [1]; + + Assert.AreEqual ("Baz", field.Name); + Assert.IsTrue (field.HasLayoutInfo); + Assert.AreEqual (2, field.Offset); + + field = fields [2]; + + Assert.AreEqual ("Gazonk", field.Name); + Assert.IsTrue (field.HasLayoutInfo); + Assert.AreEqual (4, field.Offset); + } + + [TestCSharp ("Layouts.cs")] + public void FieldRVA (ModuleDefinition module) + { + var priv_impl = GetPrivateImplementationType (module); + Assert.IsNotNull (priv_impl); + + Assert.AreEqual (1, priv_impl.Fields.Count); + + var field = priv_impl.Fields [0]; + + Assert.IsNotNull (field); + Assert.AreNotEqual (0, field.RVA); + Assert.IsNotNull (field.InitialValue); + Assert.AreEqual (16, field.InitialValue.Length); + + var buffer = new ByteBuffer (field.InitialValue); + + Assert.AreEqual (1, buffer.ReadUInt32 ()); + Assert.AreEqual (2, buffer.ReadUInt32 ()); + Assert.AreEqual (3, buffer.ReadUInt32 ()); + Assert.AreEqual (4, buffer.ReadUInt32 ()); + } + + [TestCSharp ("Generics.cs")] + public void GenericFieldDefinition (ModuleDefinition module) + { + var bar = module.GetType ("Bar`1"); + Assert.IsNotNull (bar); + + Assert.IsTrue (bar.HasGenericParameters); + var t = bar.GenericParameters [0]; + + Assert.AreEqual ("T", t.Name); + Assert.AreEqual (t.Owner, bar); + + var bang = bar.GetField ("bang"); + + Assert.IsNotNull (bang); + + Assert.AreEqual (t, bang.FieldType); + } + + [TestIL ("types.il")] + public void ArrayFields (ModuleDefinition module) + { + var types = module.GetType ("Types"); + Assert.IsNotNull (types); + + var rank_two = types.GetField ("rank_two"); + + var array = rank_two.FieldType as ArrayType; + Assert.IsNotNull (array); + + Assert.AreEqual (2, array.Rank); + Assert.IsFalse (array.Dimensions [0].IsSized); + Assert.IsFalse (array.Dimensions [1].IsSized); + + var rank_two_low_bound_zero = types.GetField ("rank_two_low_bound_zero"); + + array = rank_two_low_bound_zero.FieldType as ArrayType; + Assert.IsNotNull (array); + + Assert.AreEqual (2, array.Rank); + Assert.IsTrue (array.Dimensions [0].IsSized); + Assert.AreEqual (0, array.Dimensions [0].LowerBound); + Assert.AreEqual (null, array.Dimensions [0].UpperBound); + Assert.IsTrue (array.Dimensions [1].IsSized); + Assert.AreEqual (0, array.Dimensions [1].LowerBound); + Assert.AreEqual (null, array.Dimensions [1].UpperBound); + } + + [TestCSharp ("Fields.cs")] + public void EnumFieldsConstant (ModuleDefinition module) + { + var pim = module.GetType ("Pim"); + Assert.IsNotNull (pim); + + var field = pim.GetField ("Pam"); + Assert.IsTrue (field.HasConstant); + Assert.AreEqual (1, (int) field.Constant); + + field = pim.GetField ("Poum"); + Assert.AreEqual (2, (int) field.Constant); + } + + [TestCSharp ("Fields.cs")] + public void StringAndClassConstant (ModuleDefinition module) + { + var panpan = module.GetType ("PanPan"); + Assert.IsNotNull (panpan); + + var field = panpan.GetField ("Peter"); + Assert.IsTrue (field.HasConstant); + Assert.IsNull (field.Constant); + + field = panpan.GetField ("QQ"); + Assert.AreEqual ("qq", (string) field.Constant); + + field = panpan.GetField ("nil"); + Assert.AreEqual (null, (string) field.Constant); + } + + [TestCSharp ("Fields.cs")] + public void ObjectConstant (ModuleDefinition module) + { + var panpan = module.GetType ("PanPan"); + Assert.IsNotNull (panpan); + + var field = panpan.GetField ("obj"); + Assert.IsTrue (field.HasConstant); + Assert.IsNull (field.Constant); + } + + [TestIL ("types.il")] + public void NullPrimitiveConstant (ModuleDefinition module) + { + var fields = module.GetType ("Fields"); + + var field = fields.GetField ("int32_nullref"); + Assert.IsTrue (field.HasConstant); + Assert.AreEqual (null, field.Constant); + } + + [TestCSharp ("Fields.cs")] + public void ArrayConstant (ModuleDefinition module) + { + var panpan = module.GetType ("PanPan"); + Assert.IsNotNull (panpan); + + var field = panpan.GetField ("ints"); + Assert.IsTrue (field.HasConstant); + Assert.IsNull (field.Constant); + } + + [TestIL ("types.il")] + public void ConstantCoalescing (ModuleDefinition module) + { + var fields = module.GetType ("Fields"); + + var field = fields.GetField ("int32_int16"); + Assert.AreEqual ("System.Int32", field.FieldType.FullName); + Assert.IsTrue (field.HasConstant); + Assert.IsInstanceOfType (typeof (short), field.Constant); + Assert.AreEqual ((short) 1, field.Constant); + + field = fields.GetField ("int16_int32"); + Assert.AreEqual ("System.Int16", field.FieldType.FullName); + Assert.IsTrue (field.HasConstant); + Assert.IsInstanceOfType (typeof (int), field.Constant); + Assert.AreEqual (1, field.Constant); + + field = fields.GetField ("char_int16"); + Assert.AreEqual ("System.Char", field.FieldType.FullName); + Assert.IsTrue (field.HasConstant); + Assert.IsInstanceOfType (typeof (short), field.Constant); + Assert.AreEqual ((short) 1, field.Constant); + + field = fields.GetField ("int16_char"); + Assert.AreEqual ("System.Int16", field.FieldType.FullName); + Assert.IsTrue (field.HasConstant); + Assert.IsInstanceOfType (typeof (char), field.Constant); + Assert.AreEqual ('s', field.Constant); + } + + [TestCSharp ("Generics.cs")] + public void NestedEnumOfGenericTypeDefinition (ModuleDefinition module) + { + var dang = module.GetType ("Bongo`1/Dang"); + Assert.IsNotNull (dang); + + var field = dang.GetField ("Ding"); + Assert.IsNotNull (field); + Assert.AreEqual (2, field.Constant); + + field = dang.GetField ("Dong"); + Assert.IsNotNull (field); + Assert.AreEqual (12, field.Constant); + } + + [TestModule ("marshal.dll")] + public void MarshalAsFixedStr (ModuleDefinition module) + { + var boc = module.GetType ("Boc"); + var field = boc.GetField ("a"); + + Assert.IsNotNull (field); + + Assert.IsTrue (field.HasMarshalInfo); + + var info = (FixedSysStringMarshalInfo) field.MarshalInfo; + + Assert.AreEqual (42, info.Size); + } + + [TestModule ("marshal.dll")] + public void MarshalAsFixedArray (ModuleDefinition module) + { + var boc = module.GetType ("Boc"); + var field = boc.GetField ("b"); + + Assert.IsNotNull (field); + + Assert.IsTrue (field.HasMarshalInfo); + + var info = (FixedArrayMarshalInfo) field.MarshalInfo; + + Assert.AreEqual (12, info.Size); + Assert.AreEqual (NativeType.Boolean, info.ElementType); + } + + static TypeDefinition GetPrivateImplementationType (ModuleDefinition module) + { + foreach (var type in module.Types) + if (type.FullName.Contains ("")) + return type; + + return null; + } + + static void AssertField (TypeDefinition type, string name, Type expected) + { + var field = type.GetField (name); + Assert.IsNotNull (field, name); + + Assert.AreEqual (expected.FullName, field.FieldType.FullName); + } + } +} diff --git a/Test/Mono.Cecil.Tests/Formatter.cs b/Test/Mono.Cecil.Tests/Formatter.cs new file mode 100644 index 000000000..967896ce8 --- /dev/null +++ b/Test/Mono.Cecil.Tests/Formatter.cs @@ -0,0 +1,173 @@ +using System; +using System.IO; +using Mono.Cecil; +using Mono.Cecil.Cil; + +namespace Mono.Cecil.Tests { + + public static class Formatter { + + public static string FormatInstruction (Instruction instruction) + { + var writer = new StringWriter (); + WriteInstruction (writer, instruction); + return writer.ToString (); + } + + public static string FormatMethodBody (MethodDefinition method) + { + var writer = new StringWriter (); + WriteMethodBody (writer, method); + return writer.ToString (); + } + + public static void WriteMethodBody (TextWriter writer, MethodDefinition method) + { + var body = method.Body; + + WriteVariables (writer, body); + + foreach (Instruction instruction in body.Instructions) { + var sequence_point = instruction.SequencePoint; + if (sequence_point != null) { + writer.Write ('\t'); + WriteSequencePoint (writer, sequence_point); + writer.WriteLine (); + } + + writer.Write ('\t'); + WriteInstruction (writer, instruction); + writer.WriteLine (); + } + + WriteExceptionHandlers (writer, body); + } + + static void WriteVariables (TextWriter writer, MethodBody body) + { + var variables = body.Variables; + + writer.Write ('\t'); + writer.Write (".locals {0}(", body.InitLocals ? "init " : string.Empty); + + for (int i = 0; i < variables.Count; i++) { + if (i > 0) + writer.Write (", "); + + var variable = variables [i]; + + writer.Write ("{0} {1}", variable.VariableType, variable); + } + writer.WriteLine (")"); + } + + static void WriteInstruction (TextWriter writer, Instruction instruction) + { + writer.Write (FormatLabel (instruction.Offset)); + writer.Write (": "); + writer.Write (instruction.OpCode.Name); + if (null != instruction.Operand) { + writer.Write (' '); + WriteOperand (writer, instruction.Operand); + } + } + + static void WriteSequencePoint (TextWriter writer, SequencePoint sequence_point) + { + writer.Write (".line {0},{1}:{2},{3} '{4}'", + sequence_point.StartLine, + sequence_point.EndLine, + sequence_point.StartColumn, + sequence_point.EndColumn, + sequence_point.Document.Url); + } + + static string FormatLabel (int offset) + { + string label = "000" + offset.ToString ("x"); + return "IL_" + label.Substring (label.Length - 4); + } + + static string FormatLabel (Instruction instruction) + { + return FormatLabel (instruction.Offset); + } + + static void WriteOperand (TextWriter writer, object operand) + { + if (null == operand) throw new ArgumentNullException ("operand"); + + var target = operand as Instruction; + if (null != target) { + writer.Write (FormatLabel (target.Offset)); + return; + } + + var targets = operand as Instruction []; + if (null != targets) { + WriteLabelList (writer, targets); + return; + } + + string s = operand as string; + if (null != s) { + writer.Write ("\"" + s + "\""); + return; + } + + s = ToInvariantCultureString (operand); + writer.Write (s); + } + + static void WriteLabelList (TextWriter writer, Instruction [] instructions) + { + writer.Write ("("); + + for (int i = 0; i < instructions.Length; i++) { + if (i != 0) writer.Write (", "); + writer.Write (FormatLabel (instructions [i].Offset)); + } + + writer.Write (")"); + } + + static void WriteExceptionHandlers (TextWriter writer, MethodBody body) + { + if (!body.HasExceptionHandlers) + return; + + foreach (var handler in body.ExceptionHandlers) { + writer.Write ("\t"); + writer.WriteLine (".try {0} to {1} {2} handler {3} to {4}", + FormatLabel (handler.TryStart), + FormatLabel (handler.TryEnd), + FormatHandlerType (handler), + FormatLabel (handler.HandlerStart), + FormatLabel (handler.HandlerEnd)); + } + } + + static string FormatHandlerType (ExceptionHandler handler) + { + var handler_type = handler.HandlerType; + var type = handler_type.ToString ().ToLowerInvariant (); + + switch (handler_type) { + case ExceptionHandlerType.Catch: + return string.Format ("{0} {1}", type, handler.CatchType.FullName); + case ExceptionHandlerType.Filter: + throw new NotImplementedException (); + default: + return type; + } + } + + public static string ToInvariantCultureString (object value) + { + var convertible = value as IConvertible; + return (null != convertible) + ? convertible.ToString (System.Globalization.CultureInfo.InvariantCulture) + : value.ToString (); + } + } +} diff --git a/Test/Mono.Cecil.Tests/ILProcessorTests.cs b/Test/Mono.Cecil.Tests/ILProcessorTests.cs new file mode 100644 index 000000000..3d9d1751b --- /dev/null +++ b/Test/Mono.Cecil.Tests/ILProcessorTests.cs @@ -0,0 +1,79 @@ +using System; +using System.Linq; + +using Mono.Cecil; +using Mono.Cecil.Cil; + +using NUnit.Framework; + +namespace Mono.Cecil.Tests { + + [TestFixture] + public class ILProcessorTests : BaseTestFixture { + + [Test] + public void Append () + { + var method = CreateTestMethod (); + var il = method.GetILProcessor (); + + var ret = il.Create (OpCodes.Ret); + il.Append (ret); + + AssertOpCodeSequence (new [] { OpCodes.Ret }, method); + } + + [Test] + public void InsertBefore () + { + var method = CreateTestMethod (OpCodes.Ldloc_0, OpCodes.Ldloc_2, OpCodes.Ldloc_3); + var il = method.GetILProcessor (); + + var ldloc_2 = method.Instructions.Where (i => i.OpCode == OpCodes.Ldloc_2).First (); + + il.InsertBefore ( + ldloc_2, + il.Create (OpCodes.Ldloc_1)); + + AssertOpCodeSequence (new [] { OpCodes.Ldloc_0, OpCodes.Ldloc_1, OpCodes.Ldloc_2, OpCodes.Ldloc_3 }, method); + } + + [Test] + public void InsertAfter () + { + var method = CreateTestMethod (OpCodes.Ldloc_0, OpCodes.Ldloc_2, OpCodes.Ldloc_3); + var il = method.GetILProcessor (); + + var ldloc_0 = method.Instructions.First (); + + il.InsertAfter ( + ldloc_0, + il.Create (OpCodes.Ldloc_1)); + + AssertOpCodeSequence (new [] { OpCodes.Ldloc_0, OpCodes.Ldloc_1, OpCodes.Ldloc_2, OpCodes.Ldloc_3 }, method); + } + + static void AssertOpCodeSequence (OpCode [] expected, MethodBody body) + { + var opcodes = body.Instructions.Select (i => i.OpCode).ToArray (); + Assert.AreEqual (expected.Length, opcodes.Length); + + for (int i = 0; i < opcodes.Length; i++) + Assert.AreEqual (expected [i], opcodes [i]); + } + + static MethodBody CreateTestMethod (params OpCode [] opcodes) + { + var method = new MethodDefinition { + Name = "function", + }; + + var il = method.Body.GetILProcessor (); + + foreach (var opcode in opcodes) + il.Emit (opcode); + + return method.Body; + } + } +} diff --git a/Test/Mono.Cecil.Tests/ImageReadTests.cs b/Test/Mono.Cecil.Tests/ImageReadTests.cs new file mode 100644 index 000000000..c601fc986 --- /dev/null +++ b/Test/Mono.Cecil.Tests/ImageReadTests.cs @@ -0,0 +1,127 @@ +using System; +using System.IO; + +using Mono.Cecil; +using Mono.Cecil.PE; +using Mono.Cecil.Metadata; + +using NUnit.Framework; + +namespace Mono.Cecil.Tests { + + [TestFixture] + public class ImageReadTests : BaseTestFixture { + + [Test] + public void ImageSections () + { + var image = GetResourceImage ("hello.exe"); + + Assert.AreEqual (3, image.Sections.Length); + Assert.AreEqual (".text", image.Sections [0].Name); + Assert.AreEqual (".rsrc", image.Sections [1].Name); + Assert.AreEqual (".reloc", image.Sections [2].Name); + } + + [Test] + public void ImageMetadataVersion () + { + var image = GetResourceImage ("hello.exe"); + Assert.AreEqual (TargetRuntime.Net_2_0, image.Runtime); + + image = GetResourceImage ("hello1.exe"); + Assert.AreEqual (TargetRuntime.Net_1_1, image.Runtime); + } + + [Test] + public void ImageModuleKind () + { + var image = GetResourceImage ("hello.exe"); + Assert.AreEqual (ModuleKind.Console, image.Kind); + + image = GetResourceImage ("libhello.dll"); + Assert.AreEqual (ModuleKind.Dll, image.Kind); + + image = GetResourceImage ("hellow.exe"); + Assert.AreEqual (ModuleKind.Windows, image.Kind); + } + + [Test] + public void MetadataHeaps () + { + var image = GetResourceImage ("hello.exe"); + + Assert.IsNotNull (image.TableHeap); + + Assert.IsNotNull (image.StringHeap); + Assert.AreEqual (string.Empty, image.StringHeap.Read (0)); + Assert.AreEqual ("", image.StringHeap.Read (1)); + + Assert.IsNotNull (image.UserStringHeap); + Assert.AreEqual (string.Empty, image.UserStringHeap.Read (0)); + Assert.AreEqual ("Hello Cecil World !", image.UserStringHeap.Read (1)); + + Assert.IsNotNull (image.GuidHeap); + Assert.AreEqual (new Guid (), image.GuidHeap.Read (0)); + Assert.AreEqual (new Guid ("C3BC2BD3-2576-4D00-A80E-465B5632415F"), image.GuidHeap.Read (1)); + + Assert.IsNotNull (image.BlobHeap); + Assert.AreEqual (new byte [0], image.BlobHeap.Read (0)); + } + + [Test] + public void TablesHeap () + { + var image = GetResourceImage ("hello.exe"); + var heap = image.TableHeap; + + Assert.IsNotNull (heap); + + Assert.AreEqual (1, heap [Table.Module].Length); + Assert.AreEqual (4, heap [Table.TypeRef].Length); + Assert.AreEqual (2, heap [Table.TypeDef].Length); + Assert.AreEqual (0, heap [Table.Field].Length); + Assert.AreEqual (2, heap [Table.Method].Length); + Assert.AreEqual (4, heap [Table.MemberRef].Length); + Assert.AreEqual (2, heap [Table.CustomAttribute].Length); + Assert.AreEqual (1, heap [Table.Assembly].Length); + Assert.AreEqual (1, heap [Table.AssemblyRef].Length); + } + + [Test] + public void ReadX64Image () + { + var image = GetResourceImage ("hello.x64.exe"); + + Assert.AreEqual (TargetArchitecture.AMD64, image.Architecture); + Assert.AreEqual (ModuleAttributes.ILOnly, image.Attributes); + } + + [Test] + public void ReadIA64Image () + { + var image = GetResourceImage ("hello.ia64.exe"); + + Assert.AreEqual (TargetArchitecture.IA64, image.Architecture); + Assert.AreEqual (ModuleAttributes.ILOnly, image.Attributes); + } + + [Test] + public void ReadX86Image () + { + var image = GetResourceImage ("hello.x86.exe"); + + Assert.AreEqual (TargetArchitecture.I386, image.Architecture); + Assert.AreEqual (ModuleAttributes.ILOnly | ModuleAttributes.Required32Bit, image.Attributes); + } + + [Test] + public void ReadAnyCpuImage () + { + var image = GetResourceImage ("hello.anycpu.exe"); + + Assert.AreEqual (TargetArchitecture.I386, image.Architecture); + Assert.AreEqual (ModuleAttributes.ILOnly, image.Attributes); + } + } +} diff --git a/Test/Mono.Cecil.Tests/ImportCecilTests.cs b/Test/Mono.Cecil.Tests/ImportCecilTests.cs new file mode 100644 index 000000000..3fa04068e --- /dev/null +++ b/Test/Mono.Cecil.Tests/ImportCecilTests.cs @@ -0,0 +1,310 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Linq; +using SR = System.Reflection; +using System.Runtime.CompilerServices; + +using Mono.Cecil.Cil; + +using NUnit.Framework; + +namespace Mono.Cecil.Tests { + + [TestFixture] + public class ImportCecilTests : BaseTestFixture { + + [Test] + public void ImportStringByRef () + { + var get_string = Compile> ((module, body) => { + var type = module.Types [1]; + + var method_by_ref = new MethodDefinition { + Name = "ModifyString", + IsPrivate = true, + IsStatic = true, + }; + + type.Methods.Add (method_by_ref); + + method_by_ref.MethodReturnType.ReturnType = module.Import (typeof (void).ToDefinition ()); + + method_by_ref.Parameters.Add (new ParameterDefinition (module.Import (typeof (string).ToDefinition ()))); + method_by_ref.Parameters.Add (new ParameterDefinition (module.Import (new ByReferenceType (typeof (string).ToDefinition ())))); + + var m_il = method_by_ref.Body.GetILProcessor (); + m_il.Emit (OpCodes.Ldarg_1); + m_il.Emit (OpCodes.Ldarg_0); + m_il.Emit (OpCodes.Stind_Ref); + m_il.Emit (OpCodes.Ret); + + var v_0 = new VariableDefinition (module.Import (typeof (string).ToDefinition ())); + body.Variables.Add (v_0); + + var il = body.GetILProcessor (); + il.Emit (OpCodes.Ldnull); + il.Emit (OpCodes.Stloc, v_0); + il.Emit (OpCodes.Ldarg_0); + il.Emit (OpCodes.Ldloca, v_0); + il.Emit (OpCodes.Call, method_by_ref); + il.Emit (OpCodes.Ldloc_0); + il.Emit (OpCodes.Ret); + }); + + Assert.AreEqual ("foo", get_string ("foo")); + } + + [Test] + public void ImportStringArray () + { + var identity = Compile> ((module, body) => { + var il = body.GetILProcessor (); + il.Emit (OpCodes.Ldarg_0); + il.Emit (OpCodes.Ret); + }); + + var array = new string [2, 2]; + + Assert.AreEqual (array, identity (array)); + } + + [Test] + public void ImportFieldStringEmpty () + { + var get_empty = Compile> ((module, body) => { + var il = body.GetILProcessor (); + il.Emit (OpCodes.Ldsfld, module.Import (typeof (string).GetField ("Empty").ToDefinition ())); + il.Emit (OpCodes.Ret); + }); + + Assert.AreEqual ("", get_empty ()); + } + + [Test] + public void ImportStringConcat () + { + var concat = Compile> ((module, body) => { + var il = body.GetILProcessor (); + il.Emit (OpCodes.Ldarg_0); + il.Emit (OpCodes.Ldarg_1); + il.Emit (OpCodes.Call, module.Import (typeof (string).GetMethod ("Concat", new [] { typeof (string), typeof (string) }).ToDefinition ())); + il.Emit (OpCodes.Ret); + }); + + Assert.AreEqual ("FooBar", concat ("Foo", "Bar")); + } + + public class Generic { + public T Field; + + public T Method (T t) + { + return t; + } + + public TS GenericMethod (T t, TS s) + { + return s; + } + + public Generic ComplexGenericMethod (T t, TS s) + { + return new Generic { Field = s }; + } + } + + [Test] + public void ImportGenericField () + { + var get_field = Compile, string>> ((module, body) => { + var generic_def = module.Import (typeof (Generic<>)).Resolve (); + var field_def = generic_def.Fields.Where (f => f.Name == "Field").First (); + + var field_string = field_def.MakeGeneric (module.Import (typeof (string))); + + var field_ref = module.Import (field_string); + + var il = body.GetILProcessor (); + il.Emit (OpCodes.Ldarg_0); + il.Emit (OpCodes.Ldfld, field_ref); + il.Emit (OpCodes.Ret); + }); + + var generic = new Generic { + Field = "foo", + }; + + Assert.AreEqual ("foo", get_field (generic)); + } + + [Test] + public void ImportGenericMethod () + { + var generic_identity = Compile, int, int>> ((module, body) => { + var generic_def = module.Import (typeof (Generic<>)).Resolve (); + var method_def = generic_def.Methods.Where (m => m.Name == "Method").First (); + + var method_int = method_def.MakeGeneric (module.Import (typeof (int))); + var method_ref = module.Import (method_int); + + var il = body.GetILProcessor (); + il.Emit (OpCodes.Ldarg_0); + il.Emit (OpCodes.Ldarg_1); + il.Emit (OpCodes.Callvirt, method_ref); + il.Emit (OpCodes.Ret); + }); + + Assert.AreEqual (42, generic_identity (new Generic (), 42)); + } + + [Test] + public void ImportGenericMethodSpec () + { + var gen_spec_id = Compile, int, int>> ((module, body) => { + var generic_def = module.Import (typeof (Generic<>)).Resolve (); + var method_def = generic_def.Methods.Where (m => m.Name == "GenericMethod").First (); + + var method_string = method_def.MakeGeneric (module.Import (typeof (string))); + + var method_instance = method_string.MakeGenericMethod (module.Import (typeof (int))); + + var method_ref = module.Import (method_instance); + + var il = body.GetILProcessor (); + il.Emit (OpCodes.Ldarg_0); + il.Emit (OpCodes.Ldnull); + il.Emit (OpCodes.Ldarg_1); + il.Emit (OpCodes.Callvirt, method_ref); + il.Emit (OpCodes.Ret); + }); + + Assert.AreEqual (42, gen_spec_id (new Generic (), 42)); + } + + [Test] + public void ImportComplexGenericMethodSpec () + { + var gen_spec_id = Compile, int, int>> ((module, body) => { + var generic_def = module.Import (typeof (Generic<>)).Resolve (); + var method_def = generic_def.Methods.Where (m => m.Name == "ComplexGenericMethod").First (); + + var method_string = method_def.MakeGeneric (module.Import (typeof (string))); + var method_instance = method_string.MakeGenericMethod (module.Import (typeof (int))); + var method_ref = module.Import (method_instance); + + var field_def = generic_def.Fields.Where (f => f.Name == "Field").First (); + var field_int = field_def.MakeGeneric (module.Import (typeof (int))); + var field_ref = module.Import (field_int); + + var il = body.GetILProcessor (); + il.Emit (OpCodes.Ldarg_0); + il.Emit (OpCodes.Ldnull); + il.Emit (OpCodes.Ldarg_1); + il.Emit (OpCodes.Callvirt, method_ref); + il.Emit (OpCodes.Ldfld, field_ref); + il.Emit (OpCodes.Ret); + }); + + Assert.AreEqual (42, gen_spec_id (new Generic (), 42)); + } + + [Test] + public void ImportMethodOnOpenGeneric () + { + var generic = typeof (Generic<>).ToDefinition (); + var module = ModuleDefinition.CreateModule ("foo", ModuleKind.Dll); + + var method = module.Import (generic.GetMethod ("Method")); + + Assert.AreEqual ("T Mono.Cecil.Tests.ImportCecilTests/Generic`1::Method(T)", method.FullName); + } + + delegate void Emitter (ModuleDefinition module, MethodBody body); + + [MethodImpl (MethodImplOptions.NoInlining)] + static TDelegate Compile (Emitter emitter) + where TDelegate : class + { + var name = GetTestCaseName (); + + var module = CreateTestModule (name, emitter); + var assembly = LoadTestModule (module); + + return CreateRunDelegate (GetTestCase (name, assembly)); + } + + static TDelegate CreateRunDelegate (Type type) + where TDelegate : class + { + return (TDelegate) (object) Delegate.CreateDelegate (typeof (TDelegate), type.GetMethod ("Run")); + } + + static Type GetTestCase (string name, SR.Assembly assembly) + { + return assembly.GetType (name); + } + + static SR.Assembly LoadTestModule (ModuleDefinition module) + { + using (var stream = new MemoryStream ()) { + module.Write (stream); + File.WriteAllBytes (Path.Combine (Path.Combine (Path.GetTempPath (), "cecil"), module.Name + ".dll"), stream.ToArray ()); + return SR.Assembly.Load (stream.ToArray ()); + } + } + + static ModuleDefinition CreateTestModule (string name, Emitter emitter) + { + var module = CreateModule (name); + + var type = new TypeDefinition ( + "", + name, + TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Abstract, + module.Import (typeof (object))); + + module.Types.Add (type); + + var method = CreateMethod (type, typeof (TDelegate).GetMethod ("Invoke")); + + emitter (module, method.Body); + + return module; + } + + static MethodDefinition CreateMethod (TypeDefinition type, SR.MethodInfo pattern) + { + var module = type.Module; + + var method = new MethodDefinition { + Name = "Run", + IsPublic = true, + IsStatic = true, + }; + + type.Methods.Add (method); + + method.MethodReturnType.ReturnType = module.Import (pattern.ReturnType); + + foreach (var parameter_pattern in pattern.GetParameters ()) + method.Parameters.Add (new ParameterDefinition (module.Import (parameter_pattern.ParameterType))); + + return method; + } + + static ModuleDefinition CreateModule (string name) + { + return ModuleDefinition.CreateModule (name, ModuleKind.Dll); + } + + [MethodImpl (MethodImplOptions.NoInlining)] + static string GetTestCaseName () + { + var stack_trace = new StackTrace (); + var stack_frame = stack_trace.GetFrame (2); + + return "ImportCecil_" + stack_frame.GetMethod ().Name; + } + } +} diff --git a/Test/Mono.Cecil.Tests/ImportReflectionTests.cs b/Test/Mono.Cecil.Tests/ImportReflectionTests.cs new file mode 100644 index 000000000..dd1d28a12 --- /dev/null +++ b/Test/Mono.Cecil.Tests/ImportReflectionTests.cs @@ -0,0 +1,409 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using SR = System.Reflection; +using System.Runtime.CompilerServices; + +using Mono.Cecil.Cil; + +using NUnit.Framework; + +namespace Mono.Cecil.Tests { + + [TestFixture] + public class ImportReflectionTests : BaseTestFixture { + + [Test] + public void ImportString () + { + var get_string = Compile> ((_, body) => { + var il = body.GetILProcessor (); + il.Emit (OpCodes.Ldstr, "yo dawg!"); + il.Emit (OpCodes.Ret); + }); + + Assert.AreEqual ("yo dawg!", get_string ()); + } + + [Test] + public void ImportInt () + { + var add = Compile> ((_, body) => { + var il = body.GetILProcessor (); + il.Emit (OpCodes.Ldarg_0); + il.Emit (OpCodes.Ldarg_1); + il.Emit (OpCodes.Add); + il.Emit (OpCodes.Ret); + }); + + Assert.AreEqual (42, add (40, 2)); + } + + [Test] + public void ImportStringByRef () + { + var get_string = Compile> ((module, body) => { + var type = module.Types [1]; + + var method_by_ref = new MethodDefinition { + Name = "ModifyString", + IsPrivate = true, + IsStatic = true, + }; + + type.Methods.Add (method_by_ref); + + method_by_ref.MethodReturnType.ReturnType = module.Import (typeof (void)); + + method_by_ref.Parameters.Add (new ParameterDefinition (module.Import (typeof (string)))); + method_by_ref.Parameters.Add (new ParameterDefinition (module.Import (typeof (string).MakeByRefType ()))); + + var m_il = method_by_ref.Body.GetILProcessor (); + m_il.Emit (OpCodes.Ldarg_1); + m_il.Emit (OpCodes.Ldarg_0); + m_il.Emit (OpCodes.Stind_Ref); + m_il.Emit (OpCodes.Ret); + + var v_0 = new VariableDefinition (module.Import (typeof (string))); + body.Variables.Add (v_0); + + var il = body.GetILProcessor (); + il.Emit (OpCodes.Ldnull); + il.Emit (OpCodes.Stloc, v_0); + il.Emit (OpCodes.Ldarg_0); + il.Emit (OpCodes.Ldloca, v_0); + il.Emit (OpCodes.Call, method_by_ref); + il.Emit (OpCodes.Ldloc_0); + il.Emit (OpCodes.Ret); + }); + + Assert.AreEqual ("foo", get_string ("foo")); + } + + [Test] + public void ImportStringArray () + { + var identity = Compile> ((module, body) => { + var il = body.GetILProcessor (); + il.Emit (OpCodes.Ldarg_0); + il.Emit (OpCodes.Ret); + }); + + var array = new string [2, 2]; + + Assert.AreEqual (array, identity (array)); + } + + [Test] + public void ImportFieldStringEmpty () + { + var get_empty = Compile> ((module, body) => { + var il = body.GetILProcessor (); + il.Emit (OpCodes.Ldsfld, module.Import (typeof (string).GetField ("Empty"))); + il.Emit (OpCodes.Ret); + }); + + Assert.AreEqual ("", get_empty ()); + } + + [Test] + public void ImportStringConcat () + { + var concat = Compile> ((module, body) => { + var il = body.GetILProcessor (); + il.Emit (OpCodes.Ldarg_0); + il.Emit (OpCodes.Ldarg_1); + il.Emit (OpCodes.Call, module.Import (typeof (string).GetMethod ("Concat", new [] { typeof (string), typeof (string) }))); + il.Emit (OpCodes.Ret); + }); + + Assert.AreEqual ("FooBar", concat ("Foo", "Bar")); + } + + public class Generic { + public T Field; + + public T Method (T t) + { + return t; + } + + public TS GenericMethod (T t, TS s) + { + return s; + } + + public Generic ComplexGenericMethod (T t, TS s) + { + return new Generic { Field = s }; + } + } + + [Test] + public void ImportGenericField () + { + var get_field = Compile, string>> ((module, body) => { + var il = body.GetILProcessor (); + il.Emit (OpCodes.Ldarg_0); + il.Emit (OpCodes.Ldfld, module.Import (typeof (Generic).GetField ("Field"))); + il.Emit (OpCodes.Ret); + }); + + var generic = new Generic { + Field = "foo", + }; + + Assert.AreEqual ("foo", get_field (generic)); + } + + [Test] + public void ImportGenericMethod () + { + var generic_identity = Compile, int, int>> ((module, body) => { + var il = body.GetILProcessor (); + il.Emit (OpCodes.Ldarg_0); + il.Emit (OpCodes.Ldarg_1); + il.Emit (OpCodes.Callvirt, module.Import (typeof (Generic).GetMethod ("Method"))); + il.Emit (OpCodes.Ret); + }); + + Assert.AreEqual (42, generic_identity (new Generic (), 42)); + } + + [Test] + public void ImportGenericMethodSpec () + { + var gen_spec_id = Compile, int, int>> ((module, body) => { + var il = body.GetILProcessor (); + il.Emit (OpCodes.Ldarg_0); + il.Emit (OpCodes.Ldnull); + il.Emit (OpCodes.Ldarg_1); + il.Emit (OpCodes.Callvirt, module.Import (typeof (Generic).GetMethod ("GenericMethod").MakeGenericMethod (typeof (int)))); + il.Emit (OpCodes.Ret); + }); + + Assert.AreEqual (42, gen_spec_id (new Generic (), 42)); + } + + [Test] + public void ImportComplexGenericMethodSpec () + { + var gen_spec_id = Compile, int, int>> ((module, body) => { + var il = body.GetILProcessor (); + il.Emit (OpCodes.Ldarg_0); + il.Emit (OpCodes.Ldnull); + il.Emit (OpCodes.Ldarg_1); + il.Emit (OpCodes.Callvirt, module.Import (typeof (Generic).GetMethod ("ComplexGenericMethod").MakeGenericMethod (typeof (int)))); + il.Emit (OpCodes.Ldfld, module.Import (typeof (Generic).GetField ("Field"))); + il.Emit (OpCodes.Ret); + }); + + Assert.AreEqual (42, gen_spec_id (new Generic (), 42)); + } + + public class Foo { + public List list; + } + + [Test] + public void ImportGenericTypeDefOrOpen () + { + var module = typeof (Foo<>).ToDefinition ().Module; + + var foo_def = module.Import (typeof (Foo<>)); + var foo_open = module.Import (typeof (Foo<>), foo_def); + + Assert.AreEqual ("Mono.Cecil.Tests.ImportReflectionTests/Foo`1", foo_def.FullName); + Assert.AreEqual ("Mono.Cecil.Tests.ImportReflectionTests/Foo`1", foo_open.FullName); + } + + [Test] + public void ImportGenericTypeFromContext () + { + var list_foo = typeof (Foo<>).GetField ("list").FieldType; + var generic_list_foo_open = typeof (Generic<>).MakeGenericType (list_foo); + + var foo_def = typeof (Foo<>).ToDefinition (); + var module = foo_def.Module; + + var generic_foo = module.Import (generic_list_foo_open, foo_def); + + Assert.AreEqual ("Mono.Cecil.Tests.ImportReflectionTests/Generic`1>", + generic_foo.FullName); + } + + [Test] + public void ImportGenericTypeDefFromContext () + { + var foo_open = typeof (Foo<>).MakeGenericType (typeof (Foo<>).GetGenericArguments () [0]); + var generic_foo_open = typeof (Generic<>).MakeGenericType (foo_open); + + var foo_def = typeof (Foo<>).ToDefinition (); + var module = foo_def.Module; + + var generic_foo = module.Import (generic_foo_open, foo_def); + + Assert.AreEqual ("Mono.Cecil.Tests.ImportReflectionTests/Generic`1>", + generic_foo.FullName); + } + + [Test] + public void ImportArrayTypeDefFromContext () + { + var foo_open = typeof (Foo<>).MakeGenericType (typeof (Foo<>).GetGenericArguments () [0]); + var foo_open_array = foo_open.MakeArrayType (); + + var foo_def = typeof (Foo<>).ToDefinition (); + var module = foo_def.Module; + + var array_foo = module.Import (foo_open_array, foo_def); + + Assert.AreEqual ("Mono.Cecil.Tests.ImportReflectionTests/Foo`1[]", + array_foo.FullName); + } + + [Test] + public void ImportGenericFieldFromContext () + { + var list_foo = typeof (Foo<>).GetField ("list").FieldType; + var generic_list_foo_open = typeof (Generic<>).MakeGenericType (list_foo); + var generic_list_foo_open_field = generic_list_foo_open.GetField ("Field"); + + var foo_def = typeof (Foo<>).ToDefinition (); + var module = foo_def.Module; + + var generic_field = module.Import (generic_list_foo_open_field, foo_def); + + Assert.AreEqual ("TFoo Mono.Cecil.Tests.ImportReflectionTests/Generic`1>::Field", + generic_field.FullName); + } + + [Test] + public void ImportGenericMethodFromContext () + { + var list_foo = typeof (Foo<>).GetField ("list").FieldType; + var generic_list_foo_open = typeof (Generic<>).MakeGenericType (list_foo); + var generic_list_foo_open_method = generic_list_foo_open.GetMethod ("Method"); + + var foo_def = typeof (Foo<>).ToDefinition (); + var module = foo_def.Module; + + var generic_method = module.Import (generic_list_foo_open_method, foo_def); + + Assert.AreEqual ("TFoo Mono.Cecil.Tests.ImportReflectionTests/Generic`1>::Method(TFoo)", + generic_method.FullName); + } + + [Test] + public void ImportMethodOnOpenGenericType () + { + var module = typeof (Generic<>).ToDefinition ().Module; + + var method = module.Import (typeof (Generic<>).GetMethod ("Method")); + + Assert.AreEqual ("T Mono.Cecil.Tests.ImportReflectionTests/Generic`1::Method(T)", method.FullName); + } + + [Test] + public void ImportGenericMethodOnOpenGenericType () + { + var module = typeof (Generic<>).ToDefinition ().Module; + + var generic_method = module.Import (typeof (Generic<>).GetMethod ("GenericMethod")); + + Assert.AreEqual ("TS Mono.Cecil.Tests.ImportReflectionTests/Generic`1::GenericMethod(T,TS)", generic_method.FullName); + + generic_method = module.Import (typeof (Generic<>).GetMethod ("GenericMethod"), generic_method); + + Assert.AreEqual ("TS Mono.Cecil.Tests.ImportReflectionTests/Generic`1::GenericMethod(T,TS)", generic_method.FullName); + } + + delegate void Emitter (ModuleDefinition module, MethodBody body); + + [MethodImpl (MethodImplOptions.NoInlining)] + static TDelegate Compile (Emitter emitter) + where TDelegate : class + { + var name = GetTestCaseName (); + + var module = CreateTestModule (name, emitter); + var assembly = LoadTestModule (module); + + return CreateRunDelegate (GetTestCase (name, assembly)); + } + + static TDelegate CreateRunDelegate (Type type) + where TDelegate : class + { + return (TDelegate) (object) Delegate.CreateDelegate (typeof (TDelegate), type.GetMethod ("Run")); + } + + static Type GetTestCase (string name, SR.Assembly assembly) + { + return assembly.GetType (name); + } + + static SR.Assembly LoadTestModule (ModuleDefinition module) + { + using (var stream = new MemoryStream ()) { + module.Write (stream); + File.WriteAllBytes (Path.Combine (Path.Combine (Path.GetTempPath (), "cecil"), module.Name + ".dll"), stream.ToArray ()); + return SR.Assembly.Load (stream.ToArray ()); + } + } + + static ModuleDefinition CreateTestModule (string name, Emitter emitter) + { + var module = CreateModule (name); + + var type = new TypeDefinition ( + "", + name, + TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Abstract, + module.Import (typeof (object))); + + module.Types.Add (type); + + var method = CreateMethod (type, typeof (TDelegate).GetMethod ("Invoke")); + + emitter (module, method.Body); + + return module; + } + + static MethodDefinition CreateMethod (TypeDefinition type, SR.MethodInfo pattern) + { + var module = type.Module; + + var method = new MethodDefinition { + Name = "Run", + IsPublic = true, + IsStatic = true, + }; + + type.Methods.Add (method); + + method.MethodReturnType.ReturnType = module.Import (pattern.ReturnType); + + foreach (var parameter_pattern in pattern.GetParameters ()) + method.Parameters.Add (new ParameterDefinition (module.Import (parameter_pattern.ParameterType))); + + return method; + } + + static ModuleDefinition CreateModule (string name) + { + return ModuleDefinition.CreateModule (name, ModuleKind.Dll); + } + + [MethodImpl (MethodImplOptions.NoInlining)] + static string GetTestCaseName () + { + var stack_trace = new StackTrace (); + var stack_frame = stack_trace.GetFrame (2); + + return "ImportReflection_" + stack_frame.GetMethod ().Name; + } + } +} diff --git a/Test/Mono.Cecil.Tests/Linq.cs b/Test/Mono.Cecil.Tests/Linq.cs new file mode 100644 index 000000000..4f870e004 --- /dev/null +++ b/Test/Mono.Cecil.Tests/Linq.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; + +using Mono; + +#if !NET_3_5 && !NET_4_0 + +namespace System.Linq { + + static class Enumerable { + + public static IEnumerable Select (this IEnumerable self, Func selector) + { + foreach (var item in self) + yield return selector (item); + } + + public static IEnumerable Where (this IEnumerable self, Func predicate) + { + foreach (var item in self) + if (predicate (item)) + yield return item; + } + + public static List ToList (this IEnumerable self) + { + return new List (self); + } + + public static T [] ToArray (this IEnumerable self) + { + return self.ToList ().ToArray (); + } + + public static T First (this IEnumerable self) + { + using (var enumerator = self.GetEnumerator ()) { + if (!enumerator.MoveNext ()) + throw new InvalidOperationException (); + + return enumerator.Current; + } + } + } +} + +#endif diff --git a/Test/Mono.Cecil.Tests/MethodBodyTests.cs b/Test/Mono.Cecil.Tests/MethodBodyTests.cs new file mode 100644 index 000000000..afe8f79f9 --- /dev/null +++ b/Test/Mono.Cecil.Tests/MethodBodyTests.cs @@ -0,0 +1,363 @@ +using System; +using System.Linq; + +using Mono.Cecil; +using Mono.Cecil.Cil; + +using NUnit.Framework; + +namespace Mono.Cecil.Tests { + + [TestFixture] + public class MethodBodyTests : BaseTestFixture { + + [TestIL ("hello.il")] + public void MultiplyMethod (ModuleDefinition module) + { + var foo = module.GetType ("Foo"); + Assert.IsNotNull (foo); + + var bar = foo.GetMethod ("Bar"); + Assert.IsNotNull (bar); + Assert.IsTrue (bar.IsIL); + + AssertCode (@" + .locals init (System.Int32 V_0) + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: mul + IL_0003: stloc.0 + IL_0004: ldloc.0 + IL_0005: call System.Void Foo::Baz(System.Int32) + IL_000a: ret +", bar); + } + + [TestIL ("hello.il")] + public void PrintStringEmpty (ModuleDefinition module) + { + var foo = module.GetType ("Foo"); + Assert.IsNotNull (foo); + + var print_empty = foo.GetMethod ("PrintEmpty"); + Assert.IsNotNull (print_empty); + + AssertCode (@" + .locals () + IL_0000: ldsfld System.String System.String::Empty + IL_0005: call System.Void System.Console::WriteLine(System.String) + IL_000a: ret +", print_empty); + } + + [TestModule ("libhello.dll")] + public void Branch (ModuleDefinition module) + { + var lib = module.GetType ("Library"); + Assert.IsNotNull (lib); + + var method = lib.GetMethod ("GetHelloString"); + Assert.IsNotNull (method); + + AssertCode (@" + .locals init (System.String V_0) + IL_0000: nop + IL_0001: ldstr ""hello world of tomorrow"" + IL_0006: stloc.0 + IL_0007: br.s IL_0009 + IL_0009: ldloc.0 + IL_000a: ret +", method); + } + + [TestModule ("switch.exe")] + public void Switch (ModuleDefinition module) + { + var program = module.GetType ("Program"); + Assert.IsNotNull (program); + + var method = program.GetMethod ("Main"); + Assert.IsNotNull (method); + + AssertCode (@" + .locals init (System.Int32 V_0) + IL_0000: ldarg.0 + IL_0001: ldlen + IL_0002: conv.i4 + IL_0003: stloc.0 + IL_0004: ldloc.0 + IL_0005: ldc.i4.8 + IL_0006: bgt.s IL_0026 + IL_0008: ldloc.0 + IL_0009: ldc.i4.1 + IL_000a: sub + IL_000b: switch (IL_0032, IL_0034, IL_0038, IL_0034) + IL_0020: ldloc.0 + IL_0021: ldc.i4.8 + IL_0022: beq.s IL_0036 + IL_0024: br.s IL_0038 + IL_0026: ldloc.0 + IL_0027: ldc.i4.s 16 + IL_0029: beq.s IL_0036 + IL_002b: ldloc.0 + IL_002c: ldc.i4.s 32 + IL_002e: beq.s IL_0036 + IL_0030: br.s IL_0038 + IL_0032: ldc.i4.0 + IL_0033: ret + IL_0034: ldc.i4.1 + IL_0035: ret + IL_0036: ldc.i4.2 + IL_0037: ret + IL_0038: ldc.i4.s 42 + IL_003a: ret +", method); + } + + [TestIL ("methodspecs.il")] + public void MethodSpec (ModuleDefinition module) + { + var tamtam = module.GetType ("Tamtam"); + + var bar = tamtam.GetMethod ("Bar"); + Assert.IsNotNull (bar); + + AssertCode (@" + .locals () + IL_0000: ldc.i4.2 + IL_0001: call System.Void Tamtam::Foo(TFoo) + IL_0006: ret +", bar); + } + + [TestModule ("catch.exe")] + public void NestedTryCatchFinally (ModuleDefinition module) + { + var program = module.GetType ("Program"); + var main = program.GetMethod ("Main"); + Assert.IsNotNull (main); + + AssertCode (@" + .locals () + IL_0000: call System.Void Program::Foo() + IL_0005: leave.s IL_000d + IL_0007: call System.Void Program::Baz() + IL_000c: endfinally + IL_000d: leave.s IL_001f + IL_000f: pop + IL_0010: call System.Void Program::Bar() + IL_0015: leave.s IL_001f + IL_0017: pop + IL_0018: call System.Void Program::Bar() + IL_001d: leave.s IL_001f + IL_001f: leave.s IL_0027 + IL_0021: call System.Void Program::Baz() + IL_0026: endfinally + IL_0027: ret + .try IL_0000 to IL_0007 finally handler IL_0007 to IL_000d + .try IL_0000 to IL_000f catch System.ArgumentException handler IL_000f to IL_0017 + .try IL_0000 to IL_000f catch System.Exception handler IL_0017 to IL_001f + .try IL_0000 to IL_0021 finally handler IL_0021 to IL_0027 +", main); + } + + [TestModule ("fptr.exe", Verify = false)] + public void FunctionPointersAndCallSites (ModuleDefinition module) + { + var type = module.Types [0]; + var start = type.GetMethod ("Start"); + Assert.IsNotNull (start); + + AssertCode (@" + .locals init () + IL_0000: ldc.i4.1 + IL_0001: call method System.Int32 *(System.Int32) MakeDecision::Decide() + IL_0006: calli System.Int32(System.Int32) + IL_000b: call System.Void System.Console::WriteLine(System.Int32) + IL_0010: ldc.i4.1 + IL_0011: call method System.Int32 *(System.Int32) MakeDecision::Decide() + IL_0016: calli System.Int32(System.Int32) + IL_001b: call System.Void System.Console::WriteLine(System.Int32) + IL_0020: ldc.i4.1 + IL_0021: call method System.Int32 *(System.Int32) MakeDecision::Decide() + IL_0026: calli System.Int32(System.Int32) + IL_002b: call System.Void System.Console::WriteLine(System.Int32) + IL_0030: ret +", start); + } + + [TestIL ("hello.il")] + public void ThisParameter (ModuleDefinition module) + { + var type = module.GetType ("Foo"); + var method = type.GetMethod ("Gazonk"); + + Assert.IsNotNull (method); + + AssertCode (@" + .locals () + IL_0000: ldarg 0 + IL_0004: pop + IL_0005: ret +", method); + + Assert.AreEqual (method.Body.ThisParameter, method.Body.Instructions [0].Operand); + } + + [TestIL ("hello.il")] + public void FilterMaxStack (ModuleDefinition module) + { + var type = module.GetType ("Foo"); + var method = type.GetMethod ("TestFilter"); + + Assert.IsNotNull (method); + Assert.AreEqual (2, method.Body.MaxStackSize); + } + + [TestModule ("iterator.exe")] + public void Iterator (ModuleDefinition module) + { + var method = module.GetType ("Program").GetMethod ("GetLittleArgs"); + Assert.IsNotNull (method.Body); + } + + [TestCSharp ("CustomAttributes.cs")] + public void LoadString (ModuleDefinition module) + { + var type = module.GetType ("FooAttribute"); + var get_fiou = type.GetMethod ("get_Fiou"); + Assert.IsNotNull (get_fiou); + + var ldstr = get_fiou.Body.Instructions.Where (i => i.OpCode == OpCodes.Ldstr).First (); + Assert.AreEqual ("fiou", ldstr.Operand); + } + + static void AssertCode (string expected, MethodDefinition method) + { + Assert.IsTrue (method.HasBody); + Assert.IsNotNull (method.Body); + + Assert.AreEqual (Normalize (expected), Normalize (Formatter.FormatMethodBody (method))); + } + + static string Normalize (string str) + { + return str.Trim ().Replace ("\r\n", "\n"); + } + + [Test] + public void AddInstruction () + { + var object_ref = new TypeReference ("System", "Object", null, null, false); + var method = new MethodDefinition ("foo", MethodAttributes.Static, object_ref); + var body = new MethodBody (method); + + var il = body.GetILProcessor (); + + var first = il.Create (OpCodes.Nop); + var second = il.Create (OpCodes.Nop); + + body.Instructions.Add (first); + body.Instructions.Add (second); + + Assert.IsNull (first.Previous); + Assert.AreEqual (second, first.Next); + Assert.AreEqual (first, second.Previous); + Assert.IsNull (second.Next); + } + + [Test] + public void InsertInstruction () + { + var object_ref = new TypeReference ("System", "Object", null, null, false); + var method = new MethodDefinition ("foo", MethodAttributes.Static, object_ref); + var body = new MethodBody (method); + + var il = body.GetILProcessor (); + + var first = il.Create (OpCodes.Nop); + var second = il.Create (OpCodes.Nop); + var third = il.Create (OpCodes.Nop); + + body.Instructions.Add (first); + body.Instructions.Add (third); + + Assert.IsNull (first.Previous); + Assert.AreEqual (third, first.Next); + Assert.AreEqual (first, third.Previous); + Assert.IsNull (third.Next); + + body.Instructions.Insert (1, second); + + Assert.IsNull (first.Previous); + Assert.AreEqual (second, first.Next); + Assert.AreEqual (first, second.Previous); + Assert.AreEqual (third, second.Next); + Assert.AreEqual (second, third.Previous); + Assert.IsNull (third.Next); + } + + [Test] + public void InsertAfterLastInstruction () + { + var object_ref = new TypeReference ("System", "Object", null, null, false); + var method = new MethodDefinition ("foo", MethodAttributes.Static, object_ref); + var body = new MethodBody (method); + + var il = body.GetILProcessor (); + + var first = il.Create (OpCodes.Nop); + var second = il.Create (OpCodes.Nop); + var third = il.Create (OpCodes.Nop); + + body.Instructions.Add (first); + body.Instructions.Add (second); + + Assert.IsNull (first.Previous); + Assert.AreEqual (second, first.Next); + Assert.AreEqual (first, second.Previous); + Assert.IsNull (second.Next); + + body.Instructions.Insert (2, third); + + Assert.IsNull (first.Previous); + Assert.AreEqual (second, first.Next); + Assert.AreEqual (first, second.Previous); + Assert.AreEqual (third, second.Next); + Assert.AreEqual (second, third.Previous); + Assert.IsNull (third.Next); + } + + [Test] + public void RemoveInstruction () + { + var object_ref = new TypeReference ("System", "Object", null, null, false); + var method = new MethodDefinition ("foo", MethodAttributes.Static, object_ref); + var body = new MethodBody (method); + + var il = body.GetILProcessor (); + + var first = il.Create (OpCodes.Nop); + var second = il.Create (OpCodes.Nop); + var third = il.Create (OpCodes.Nop); + + body.Instructions.Add (first); + body.Instructions.Add (second); + body.Instructions.Add (third); + + Assert.IsNull (first.Previous); + Assert.AreEqual (second, first.Next); + Assert.AreEqual (first, second.Previous); + Assert.AreEqual (third, second.Next); + Assert.AreEqual (second, third.Previous); + Assert.IsNull (third.Next); + + body.Instructions.Remove (second); + + Assert.IsNull (first.Previous); + Assert.AreEqual (third, first.Next); + Assert.AreEqual (first, third.Previous); + Assert.IsNull (third.Next); + } + } +} diff --git a/Test/Mono.Cecil.Tests/MethodTests.cs b/Test/Mono.Cecil.Tests/MethodTests.cs new file mode 100644 index 000000000..c7d55f9a3 --- /dev/null +++ b/Test/Mono.Cecil.Tests/MethodTests.cs @@ -0,0 +1,193 @@ +using System; +using System.Linq; + +using Mono.Cecil; +using Mono.Cecil.Metadata; + +using NUnit.Framework; + +namespace Mono.Cecil.Tests { + + [TestFixture] + public class MethodTests : BaseTestFixture { + + [TestCSharp ("Methods.cs")] + public void AbstractMethod (ModuleDefinition module) + { + var type = module.Types [1]; + Assert.AreEqual ("Foo", type.Name); + Assert.AreEqual (2, type.Methods.Count); + + var method = type.GetMethod ("Bar"); + Assert.AreEqual ("Bar", method.Name); + Assert.IsTrue (method.IsAbstract); + Assert.IsNotNull (method.ReturnType); + + Assert.AreEqual (1, method.Parameters.Count); + + var parameter = method.Parameters [0]; + + Assert.AreEqual ("a", parameter.Name); + Assert.AreEqual ("System.Int32", parameter.ParameterType.FullName); + } + + [TestCSharp ("Methods.cs")] + public void SimplePInvoke (ModuleDefinition module) + { + var bar = module.GetType ("Bar"); + var pan = bar.GetMethod ("Pan"); + + Assert.IsTrue (pan.IsPInvokeImpl); + Assert.IsNotNull (pan.PInvokeInfo); + + Assert.AreEqual ("Pan", pan.PInvokeInfo.EntryPoint); + Assert.IsNotNull (pan.PInvokeInfo.Module); + Assert.AreEqual ("foo.dll", pan.PInvokeInfo.Module.Name); + } + + [TestCSharp ("Generics.cs")] + public void GenericMethodDefinition (ModuleDefinition module) + { + var baz = module.GetType ("Baz"); + + var gazonk = baz.GetMethod ("Gazonk"); + + Assert.IsNotNull (gazonk); + + Assert.IsTrue (gazonk.HasGenericParameters); + Assert.AreEqual (1, gazonk.GenericParameters.Count); + Assert.AreEqual ("TBang", gazonk.GenericParameters [0].Name); + } + + [TestCSharp ("Generics.cs")] + public void ReturnGenericInstance (ModuleDefinition module) + { + var bar = module.GetType ("Bar`1"); + + var self = bar.GetMethod ("Self"); + Assert.IsNotNull (self); + + var bar_t = self.ReturnType; + + Assert.IsTrue (bar_t.IsGenericInstance); + + var bar_t_instance = (GenericInstanceType) bar_t; + + Assert.AreEqual (bar.GenericParameters [0], bar_t_instance.GenericArguments [0]); + + var self_str = bar.GetMethod ("SelfString"); + Assert.IsNotNull (self_str); + + var bar_str = self_str.ReturnType; + Assert.IsTrue (bar_str.IsGenericInstance); + + var bar_str_instance = (GenericInstanceType) bar_str; + + Assert.AreEqual ("System.String", bar_str_instance.GenericArguments [0].FullName); + } + + [TestCSharp ("Generics.cs")] + public void ReturnGenericInstanceWithMethodParameter (ModuleDefinition module) + { + var baz = module.GetType ("Baz"); + + var gazoo = baz.GetMethod ("Gazoo"); + Assert.IsNotNull (gazoo); + + var bar_bingo = gazoo.ReturnType; + + Assert.IsTrue (bar_bingo.IsGenericInstance); + + var bar_bingo_instance = (GenericInstanceType) bar_bingo; + + Assert.AreEqual (gazoo.GenericParameters [0], bar_bingo_instance.GenericArguments [0]); + } + + [TestCSharp ("Interfaces.cs")] + public void SimpleOverrides (ModuleDefinition module) + { + var ibingo = module.GetType ("IBingo"); + var ibingo_foo = ibingo.GetMethod ("Foo"); + Assert.IsNotNull (ibingo_foo); + + var ibingo_bar = ibingo.GetMethod ("Bar"); + Assert.IsNotNull (ibingo_bar); + + var bingo = module.GetType ("Bingo"); + + var foo = bingo.GetMethod ("IBingo.Foo"); + Assert.IsNotNull (foo); + + Assert.IsTrue (foo.HasOverrides); + Assert.AreEqual (ibingo_foo, foo.Overrides [0]); + + var bar = bingo.GetMethod ("IBingo.Bar"); + Assert.IsNotNull (bar); + + Assert.IsTrue (bar.HasOverrides); + Assert.AreEqual (ibingo_bar, bar.Overrides [0]); + } + + [TestModule ("varargs.exe")] + public void VarArgs (ModuleDefinition module) + { + var module_type = module.Types [0]; + + Assert.AreEqual (3, module_type.Methods.Count); + + var bar = module_type.GetMethod ("Bar"); + var baz = module_type.GetMethod ("Baz"); + var foo = module_type.GetMethod ("Foo"); + + Assert.IsTrue (bar.IsVarArg ()); + Assert.IsFalse (baz.IsVarArg ()); + + Assert.IsTrue(foo.IsVarArg ()); + + var bar_reference = (MethodReference) baz.Body.Instructions.Where (i => i.Offset == 0x000a).First ().Operand; + + Assert.IsTrue (bar_reference.IsVarArg ()); + Assert.AreEqual (0, bar_reference.GetSentinelPosition ()); + + var foo_reference = (MethodReference) baz.Body.Instructions.Where (i => i.Offset == 0x0023).First ().Operand; + + Assert.IsTrue (foo_reference.IsVarArg ()); + + Assert.AreEqual (1, foo_reference.GetSentinelPosition ()); + } + + [TestCSharp ("Generics.cs")] + public void GenericInstanceMethod (ModuleDefinition module) + { + var type = module.GetType ("It"); + var method = type.GetMethod ("ReadPwow"); + + GenericInstanceMethod instance = null; + + foreach (var instruction in method.Body.Instructions) { + instance = instruction.Operand as GenericInstanceMethod; + if (instance != null) + break; + } + + Assert.IsNotNull (instance); + + Assert.AreEqual (TokenType.MethodSpec, instance.MetadataToken.TokenType); + Assert.AreNotEqual (0, instance.MetadataToken.RID); + } + + [TestCSharp ("Generics.cs")] + public void MethodRefDeclaredOnGenerics (ModuleDefinition module) + { + var type = module.GetType ("Tamtam"); + var beta = type.GetMethod ("Beta"); + var charlie = type.GetMethod ("Charlie"); + + var new_list_beta = (MethodReference) beta.Body.Instructions [0].Operand; + var new_list_charlie = (MethodReference) charlie.Body.Instructions [0].Operand; + + Assert.AreEqual ("System.Collections.Generic.List`1", new_list_beta.DeclaringType.FullName); + Assert.AreEqual ("System.Collections.Generic.List`1", new_list_charlie.DeclaringType.FullName); + } + } +} diff --git a/Test/Mono.Cecil.Tests/ModuleTests.cs b/Test/Mono.Cecil.Tests/ModuleTests.cs new file mode 100644 index 000000000..ba9ebfc0e --- /dev/null +++ b/Test/Mono.Cecil.Tests/ModuleTests.cs @@ -0,0 +1,240 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Linq; + +using Mono.Cecil; + +using NUnit.Framework; + +namespace Mono.Cecil.Tests { + + [TestFixture] + public class ModuleTests : BaseTestFixture { + + [TestModule ("hello.exe")] + public void SingleModule (ModuleDefinition module) + { + var assembly = module.Assembly; + + Assert.AreEqual (1, assembly.Modules.Count); + Assert.IsNotNull (assembly.MainModule); + } + + [TestModule ("hello.exe")] + public void EntryPoint (ModuleDefinition module) + { + var entry_point = module.EntryPoint; + Assert.IsNotNull (entry_point); + + Assert.AreEqual ("System.Void Program::Main()", entry_point.ToString ()); + } + + [TestModule ("mma.exe")] + public void MultiModules (ModuleDefinition module) + { + var assembly = module.Assembly; + + Assert.AreEqual (3, assembly.Modules.Count); + + Assert.AreEqual ("mma.exe", assembly.Modules [0].Name); + Assert.AreEqual (ModuleKind.Console, assembly.Modules [0].Kind); + + Assert.AreEqual ("moda.netmodule", assembly.Modules [1].Name); + Assert.AreEqual ("eedb4721-6c3e-4d9a-be30-49021121dd92", assembly.Modules [1].Mvid.ToString ()); + Assert.AreEqual (ModuleKind.NetModule, assembly.Modules [1].Kind); + + Assert.AreEqual ("modb.netmodule", assembly.Modules [2].Name); + Assert.AreEqual ("46c5c577-11b2-4ea0-bb3c-3c71f1331dd0", assembly.Modules [2].Mvid.ToString ()); + Assert.AreEqual (ModuleKind.NetModule, assembly.Modules [2].Kind); + } + + [TestModule ("hello.exe")] + public void ModuleInformation (ModuleDefinition module) + { + Assert.IsNotNull (module); + + Assert.AreEqual ("hello.exe", module.Name); + Assert.AreEqual (new Guid ("C3BC2BD3-2576-4D00-A80E-465B5632415F"), module.Mvid); + } + + [TestModule ("hello.exe")] + public void AssemblyReferences (ModuleDefinition module) + { + Assert.AreEqual (1, module.AssemblyReferences.Count); + + var reference = module.AssemblyReferences [0]; + + Assert.AreEqual ("mscorlib", reference.Name); + Assert.AreEqual (new Version (2, 0, 0, 0), reference.Version); + Assert.AreEqual (new byte [] { 0xB7, 0x7A, 0x5C, 0x56, 0x19, 0x34, 0xE0, 0x89 }, reference.PublicKeyToken); + } + + [TestModule ("pinvoke.exe")] + public void ModuleReferences (ModuleDefinition module) + { + Assert.AreEqual (2, module.ModuleReferences.Count); + Assert.AreEqual ("kernel32.dll", module.ModuleReferences [0].Name); + Assert.AreEqual ("shell32.dll", module.ModuleReferences [1].Name); + } + + [TestModule ("hello.exe")] + public void Types (ModuleDefinition module) + { + Assert.AreEqual (2, module.Types.Count); + Assert.AreEqual ("", module.Types [0].FullName); + Assert.AreEqual ("", module.GetType ("").FullName); + Assert.AreEqual ("Program", module.Types [1].FullName); + Assert.AreEqual ("Program", module.GetType ("Program").FullName); + } + + [TestModule ("libres.dll")] + public void LinkedResource (ModuleDefinition module) + { + var resource = module.Resources.Where (res => res.Name == "linked.txt").First () as LinkedResource; + Assert.IsNotNull (resource); + + Assert.AreEqual ("linked.txt", resource.Name); + Assert.AreEqual ("linked.txt", resource.File); + Assert.AreEqual (ResourceType.Linked, resource.ResourceType); + Assert.IsTrue (resource.IsPublic); + } + + [TestModule ("libres.dll")] + public void EmbeddedResource (ModuleDefinition module) + { + var resource = module.Resources.Where (res => res.Name == "embedded1.txt").First () as EmbeddedResource; + Assert.IsNotNull (resource); + + Assert.AreEqual ("embedded1.txt", resource.Name); + Assert.AreEqual (ResourceType.Embedded, resource.ResourceType); + Assert.IsTrue (resource.IsPublic); + + using (var reader = new StreamReader (resource.GetResourceStream ())) + Assert.AreEqual ("Hello", reader.ReadToEnd ()); + + resource = module.Resources.Where (res => res.Name == "embedded2.txt").First () as EmbeddedResource; + Assert.IsNotNull (resource); + + Assert.AreEqual ("embedded2.txt", resource.Name); + Assert.AreEqual (ResourceType.Embedded, resource.ResourceType); + Assert.IsTrue (resource.IsPublic); + + using (var reader = new StreamReader (resource.GetResourceStream ())) + Assert.AreEqual ("World", reader.ReadToEnd ()); + } + + [TestModule ("mma.exe")] + public void ExportedTypeFromNetModule (ModuleDefinition module) + { + Assert.IsTrue (module.HasExportedTypes); + Assert.AreEqual (2, module.ExportedTypes.Count); + + var exported_type = module.ExportedTypes [0]; + + Assert.AreEqual ("Module.A.Foo", exported_type.FullName); + Assert.AreEqual ("moda.netmodule", exported_type.Scope.Name); + + exported_type = module.ExportedTypes [1]; + + Assert.AreEqual ("Module.B.Baz", exported_type.FullName); + Assert.AreEqual ("modb.netmodule", exported_type.Scope.Name); + } + + [TestCSharp ("CustomAttributes.cs")] + public void NestedTypeForwarder (ModuleDefinition module) + { + Assert.IsTrue (module.HasExportedTypes); + Assert.AreEqual (2, module.ExportedTypes.Count); + + var exported_type = module.ExportedTypes [0]; + + Assert.AreEqual ("System.Diagnostics.DebuggableAttribute", exported_type.FullName); + Assert.AreEqual ("mscorlib", exported_type.Scope.Name); + Assert.IsTrue (exported_type.IsForwarder); + + var nested_exported_type = module.ExportedTypes [1]; + + Assert.AreEqual ("System.Diagnostics.DebuggableAttribute/DebuggingModes", nested_exported_type.FullName); + Assert.AreEqual (exported_type, nested_exported_type.DeclaringType); + Assert.AreEqual ("mscorlib", nested_exported_type.Scope.Name); + } + + [TestCSharp ("CustomAttributes.cs")] + public void HasTypeReference (ModuleDefinition module) + { + Assert.IsTrue (module.HasTypeReference ("System.Attribute")); + Assert.IsTrue (module.HasTypeReference ("mscorlib", "System.Attribute")); + + Assert.IsFalse (module.HasTypeReference ("System.Core", "System.Attribute")); + Assert.IsFalse (module.HasTypeReference ("System.Linq.Enumerable")); + } + + [TestModule ("libhello.dll")] + public void Win32FileVersion (ModuleDefinition module) + { + var version = FileVersionInfo.GetVersionInfo (module.FullyQualifiedName); + + Assert.AreEqual ("0.0.0.0", version.FileVersion); + } + + [TestModule ("noblob.dll")] + public void ModuleWithoutBlob (ModuleDefinition module) + { + Assert.IsNull (module.Image.BlobHeap); + } + + [Test] + public void MixedModeModule () + { + var module = GetResourceModule ("cppcli.dll"); + + Assert.AreEqual (1, module.ModuleReferences.Count); + Assert.AreEqual (string.Empty, module.ModuleReferences [0].Name); + } + + [Test] + [ExpectedException (typeof (BadImageFormatException))] + public void OpenIrrelevantFile () + { + GetResourceModule ("text_file.txt"); + } + + [Test] + public void WriteModuleTwice () + { + var module = GetResourceModule ("iterator.exe"); + + var path = Path.Combine (Path.GetTempPath (), "cecil"); + var file = Path.Combine (path, "iteratorrt.exe"); + + module.Write (file); + module.Write (file); + } + + [Test] + public void GetTypeNamespacePlusName () + { + var module = GetResourceModule ("moda.netmodule"); + + var type = module.GetType ("Module.A", "Foo"); + Assert.IsNotNull (type); + } + + [Test] + public void OpenModuleImmediate () + { + var module = GetResourceModule ("hello.exe", ReadingMode.Immediate); + + Assert.AreEqual (ReadingMode.Immediate, module.ReadingMode); + } + + [Test] + public void OpenModuleDeferred () + { + var module = GetResourceModule ("hello.exe", ReadingMode.Deferred); + + Assert.AreEqual (ReadingMode.Deferred, module.ReadingMode); + } + } +} diff --git a/Test/Mono.Cecil.Tests/NestedTypesTests.cs b/Test/Mono.Cecil.Tests/NestedTypesTests.cs new file mode 100644 index 000000000..a8392928b --- /dev/null +++ b/Test/Mono.Cecil.Tests/NestedTypesTests.cs @@ -0,0 +1,45 @@ +using System; + +using Mono.Cecil; + +using NUnit.Framework; + +namespace Mono.Cecil.Tests { + + [TestFixture] + public class NestedTypesTests : BaseTestFixture { + + [TestCSharp ("NestedTypes.cs")] + public void NestedTypes (ModuleDefinition module) + { + var foo = module.GetType ("Foo"); + + Assert.AreEqual ("Foo", foo.Name); + Assert.AreEqual ("Foo", foo.FullName); + Assert.AreEqual (module, foo.Module); + Assert.AreEqual (1, foo.NestedTypes.Count); + + var bar = foo.NestedTypes [0]; + + Assert.AreEqual ("Bar", bar.Name); + Assert.AreEqual ("Foo/Bar", bar.FullName); + Assert.AreEqual (module, bar.Module); + Assert.AreEqual (1, bar.NestedTypes.Count); + + var baz = bar.NestedTypes [0]; + + Assert.AreEqual ("Baz", baz.Name); + Assert.AreEqual ("Foo/Bar/Baz", baz.FullName); + Assert.AreEqual (module, baz.Module); + } + + [TestCSharp ("NestedTypes.cs")] + public void DirectNestedType (ModuleDefinition module) + { + var bingo = module.GetType ("Bingo"); + var get_fuel = bingo.GetMethod ("GetFuel"); + + Assert.AreEqual ("Bingo/Fuel", get_fuel.ReturnType.FullName); + } + } +} diff --git a/Test/Mono.Cecil.Tests/ParameterTests.cs b/Test/Mono.Cecil.Tests/ParameterTests.cs new file mode 100644 index 000000000..124d7e1bd --- /dev/null +++ b/Test/Mono.Cecil.Tests/ParameterTests.cs @@ -0,0 +1,224 @@ +using System; +using System.Linq; + +using Mono.Cecil; +using Mono.Cecil.Metadata; + +using NUnit.Framework; + +namespace Mono.Cecil.Tests { + + [TestFixture] + public class ParameterTests : BaseTestFixture { + + [TestModule ("marshal.dll")] + public void MarshalAsI4 (ModuleDefinition module) + { + var bar = module.GetType ("Bar"); + var pan = bar.GetMethod ("Pan"); + + Assert.AreEqual (1, pan.Parameters.Count); + + var parameter = pan.Parameters [0]; + + Assert.IsTrue (parameter.HasMarshalInfo); + var info = parameter.MarshalInfo; + + Assert.AreEqual (typeof (MarshalInfo), info.GetType ()); + Assert.AreEqual (NativeType.I4, info.NativeType); + } + + [TestModule ("marshal.dll")] + public void CustomMarshaler (ModuleDefinition module) + { + var bar = module.GetType ("Bar"); + var pan = bar.GetMethod ("PanPan"); + + var parameter = pan.Parameters [0]; + + Assert.IsTrue (parameter.HasMarshalInfo); + + var info = (CustomMarshalInfo) parameter.MarshalInfo; + + Assert.AreEqual (Guid.Empty, info.Guid); + Assert.AreEqual (string.Empty, info.UnmanagedType); + Assert.AreEqual (NativeType.CustomMarshaler, info.NativeType); + Assert.AreEqual ("nomnom", info.Cookie); + + Assert.AreEqual ("Boc", info.ManagedType.FullName); + Assert.AreEqual (module, info.ManagedType.Scope); + } + + [TestModule ("marshal.dll")] + public void SafeArrayMarshaler (ModuleDefinition module) + { + var bar = module.GetType ("Bar"); + var pan = bar.GetMethod ("PanPan"); + + Assert.IsTrue (pan.MethodReturnType.HasMarshalInfo); + + var info = (SafeArrayMarshalInfo) pan.MethodReturnType.MarshalInfo; + + Assert.AreEqual (VariantType.Dispatch, info.ElementType); + } + + [TestModule ("marshal.dll")] + public void ArrayMarshaler (ModuleDefinition module) + { + var bar = module.GetType ("Bar"); + var pan = bar.GetMethod ("PanPan"); + + var parameter = pan.Parameters [1]; + + Assert.IsTrue (parameter.HasMarshalInfo); + + var info = (ArrayMarshalInfo) parameter.MarshalInfo; + + Assert.AreEqual (NativeType.I8, info.ElementType); + Assert.AreEqual (66, info.Size); + Assert.AreEqual (2, info.SizeParameterIndex); + + parameter = pan.Parameters [3]; + + Assert.IsTrue (parameter.HasMarshalInfo); + + info = (ArrayMarshalInfo) parameter.MarshalInfo; + + Assert.AreEqual (NativeType.I2, info.ElementType); + Assert.AreEqual (-1, info.Size); + Assert.AreEqual (-1, info.SizeParameterIndex); + } + + [TestModule ("marshal.dll")] + public void ArrayMarshalerSized (ModuleDefinition module) + { + var delegate_type = module.GetType ("SomeMethod"); + var parameter = delegate_type.GetMethod ("Invoke").Parameters [1]; + + Assert.IsTrue (parameter.HasMarshalInfo); + var array_info = (ArrayMarshalInfo) parameter.MarshalInfo; + + Assert.IsNotNull (array_info); + + Assert.AreEqual (0, array_info.SizeParameterMultiplier); + } + + [TestModule ("boxedoptarg.dll")] + public void BoxedDefaultArgumentValue (ModuleDefinition module) + { + var foo = module.GetType ("Foo"); + var bar = foo.GetMethod ("Bar"); + var baz = bar.Parameters [0]; + + Assert.IsTrue (baz.HasConstant); + Assert.AreEqual (-1, baz.Constant); + } + + [Test] + public void AddParameterIndex () + { + var object_ref = new TypeReference ("System", "Object", null, null, false); + var method = new MethodDefinition ("foo", MethodAttributes.Static, object_ref); + + var x = new ParameterDefinition ("x", ParameterAttributes.None, object_ref); + var y = new ParameterDefinition ("y", ParameterAttributes.None, object_ref); + + method.Parameters.Add (x); + method.Parameters.Add (y); + + Assert.AreEqual (0, x.Index); + Assert.AreEqual (1, y.Index); + + Assert.AreEqual (method, x.Method); + Assert.AreEqual (method, y.Method); + } + + [Test] + public void RemoveAtParameterIndex () + { + var object_ref = new TypeReference ("System", "Object", null, null, false); + var method = new MethodDefinition ("foo", MethodAttributes.Static, object_ref); + + var x = new ParameterDefinition ("x", ParameterAttributes.None, object_ref); + var y = new ParameterDefinition ("y", ParameterAttributes.None, object_ref); + var z = new ParameterDefinition ("y", ParameterAttributes.None, object_ref); + + method.Parameters.Add (x); + method.Parameters.Add (y); + method.Parameters.Add (z); + + Assert.AreEqual (0, x.Index); + Assert.AreEqual (1, y.Index); + Assert.AreEqual (2, z.Index); + + method.Parameters.RemoveAt (1); + + Assert.AreEqual (0, x.Index); + Assert.AreEqual (-1, y.Index); + Assert.AreEqual (1, z.Index); + } + + [Test] + public void RemoveParameterIndex () + { + var object_ref = new TypeReference ("System", "Object", null, null, false); + var method = new MethodDefinition ("foo", MethodAttributes.Static, object_ref); + + var x = new ParameterDefinition ("x", ParameterAttributes.None, object_ref); + var y = new ParameterDefinition ("y", ParameterAttributes.None, object_ref); + var z = new ParameterDefinition ("y", ParameterAttributes.None, object_ref); + + method.Parameters.Add (x); + method.Parameters.Add (y); + method.Parameters.Add (z); + + Assert.AreEqual (0, x.Index); + Assert.AreEqual (1, y.Index); + Assert.AreEqual (2, z.Index); + + method.Parameters.Remove (y); + + Assert.AreEqual (0, x.Index); + Assert.AreEqual (-1, y.Index); + Assert.AreEqual (1, z.Index); + } + + [Test] + public void InsertParameterIndex () + { + var object_ref = new TypeReference ("System", "Object", null, null, false); + var method = new MethodDefinition ("foo", MethodAttributes.Static, object_ref); + + var x = new ParameterDefinition ("x", ParameterAttributes.None, object_ref); + var y = new ParameterDefinition ("y", ParameterAttributes.None, object_ref); + var z = new ParameterDefinition ("y", ParameterAttributes.None, object_ref); + + method.Parameters.Add (x); + method.Parameters.Add (z); + + Assert.AreEqual (0, x.Index); + Assert.AreEqual (-1, y.Index); + Assert.AreEqual (1, z.Index); + + method.Parameters.Insert (1, y); + + Assert.AreEqual (0, x.Index); + Assert.AreEqual (1, y.Index); + Assert.AreEqual (2, z.Index); + } + + [TestIL ("hello.il")] + public void GenericParameterConstant (ModuleDefinition module) + { + var foo = module.GetType ("Foo"); + var method = foo.GetMethod ("GetState"); + + Assert.IsNotNull (method); + + var parameter = method.Parameters [1]; + + Assert.IsTrue (parameter.HasConstant); + Assert.IsNull (parameter.Constant); + } + } +} diff --git a/Test/Mono.Cecil.Tests/PropertyTests.cs b/Test/Mono.Cecil.Tests/PropertyTests.cs new file mode 100644 index 000000000..2ff9c9285 --- /dev/null +++ b/Test/Mono.Cecil.Tests/PropertyTests.cs @@ -0,0 +1,112 @@ +using System.Linq; + +using NUnit.Framework; + +namespace Mono.Cecil.Tests { + + [TestFixture] + public class PropertyTests : BaseTestFixture { + + [TestCSharp ("Properties.cs")] + public void AbstractMethod (ModuleDefinition module) + { + var type = module.GetType ("Foo"); + + Assert.IsTrue (type.HasProperties); + + var properties = type.Properties; + + Assert.AreEqual (3, properties.Count); + + var property = properties [0]; + + Assert.IsNotNull (property); + Assert.AreEqual ("Bar", property.Name); + Assert.IsNotNull (property.PropertyType); + Assert.AreEqual ("System.Int32", property.PropertyType.FullName); + + Assert.IsNotNull (property.GetMethod); + Assert.AreEqual (MethodSemanticsAttributes.Getter, property.GetMethod.SemanticsAttributes); + Assert.IsNull (property.SetMethod); + + property = properties [1]; + + Assert.IsNotNull (property); + Assert.AreEqual ("Baz", property.Name); + Assert.IsNotNull (property.PropertyType); + Assert.AreEqual ("System.String", property.PropertyType.FullName); + + Assert.IsNotNull (property.GetMethod); + Assert.AreEqual (MethodSemanticsAttributes.Getter, property.GetMethod.SemanticsAttributes); + Assert.IsNotNull (property.SetMethod); + Assert.AreEqual (MethodSemanticsAttributes.Setter, property.SetMethod.SemanticsAttributes); + + property = properties [2]; + + Assert.IsNotNull (property); + Assert.AreEqual ("Gazonk", property.Name); + Assert.IsNotNull (property.PropertyType); + Assert.AreEqual ("System.String", property.PropertyType.FullName); + + Assert.IsNull (property.GetMethod); + Assert.IsNotNull (property.SetMethod); + Assert.AreEqual (MethodSemanticsAttributes.Setter, property.SetMethod.SemanticsAttributes); + } + + [TestIL ("others.il")] + public void OtherMethod (ModuleDefinition module) + { + var type = module.GetType ("Others"); + + Assert.IsTrue (type.HasProperties); + + var properties = type.Properties; + + Assert.AreEqual (1, properties.Count); + + var property = properties [0]; + + Assert.IsNotNull (property); + Assert.AreEqual ("Context", property.Name); + Assert.IsNotNull (property.PropertyType); + Assert.AreEqual ("System.String", property.PropertyType.FullName); + + Assert.IsTrue (property.HasOtherMethods); + + Assert.AreEqual (2, property.OtherMethods.Count); + + var other = property.OtherMethods [0]; + Assert.AreEqual ("let_Context", other.Name); + + other = property.OtherMethods [1]; + Assert.AreEqual ("bet_Context", other.Name); + } + + [TestCSharp ("Properties.cs")] + public void SetOnlyIndexer (ModuleDefinition module) + { + var type = module.GetType ("Bar"); + var indexer = type.Properties.Where (property => property.Name == "Item").First (); + + var parameters = indexer.Parameters; + + Assert.AreEqual (2, parameters.Count); + Assert.AreEqual ("System.Int32", parameters [0].ParameterType.FullName); + Assert.AreEqual ("System.String", parameters [1].ParameterType.FullName); + } + + [TestCSharp ("Properties.cs")] + public void ReadSemanticsFirst (ModuleDefinition module) + { + var type = module.GetType ("Baz"); + var setter = type.GetMethod ("set_Bingo"); + + Assert.AreEqual (MethodSemanticsAttributes.Setter, setter.SemanticsAttributes); + + var property = type.Properties.Where (p => p.Name == "Bingo").First (); + + Assert.AreEqual (setter, property.SetMethod); + Assert.AreEqual (type.GetMethod ("get_Bingo"), property.GetMethod); + } + } +} diff --git a/Test/Mono.Cecil.Tests/ResolveTests.cs b/Test/Mono.Cecil.Tests/ResolveTests.cs new file mode 100644 index 000000000..9ec1be8f2 --- /dev/null +++ b/Test/Mono.Cecil.Tests/ResolveTests.cs @@ -0,0 +1,262 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +using Mono.Cecil; +using Mono.Cecil.Cil; + +using NUnit.Framework; + +namespace Mono.Cecil.Tests { + + [TestFixture] + public class ResolveTests : BaseTestFixture { + + [Test] + public void StringEmpty () + { + var string_empty = GetReference, FieldReference> ( + () => string.Empty); + + Assert.AreEqual ("System.String System.String::Empty", string_empty.FullName); + + var definition = string_empty.Resolve (); + + Assert.IsNotNull (definition); + + Assert.AreEqual ("System.String System.String::Empty", definition.FullName); + Assert.AreEqual ("mscorlib", definition.Module.Assembly.Name.Name); + } + + delegate string GetSubstring (string str, int start, int length); + + [Test] + public void StringSubstring () + { + var string_substring = GetReference ( + (s, start, length) => s.Substring (start, length)); + + var definition = string_substring.Resolve (); + + Assert.IsNotNull (definition); + + Assert.AreEqual ("System.String System.String::Substring(System.Int32,System.Int32)", definition.FullName); + Assert.AreEqual ("mscorlib", definition.Module.Assembly.Name.Name); + } + + [Test] + public void StringLength () + { + var string_length = GetReference, MethodReference> (s => s.Length); + + var definition = string_length.Resolve (); + + Assert.IsNotNull (definition); + + Assert.AreEqual ("get_Length", definition.Name); + Assert.AreEqual ("System.String", definition.DeclaringType.FullName); + Assert.AreEqual ("mscorlib", definition.Module.Assembly.Name.Name); + } + + [Test] + public void ListOfStringAdd () + { + var list_add = GetReference>, MethodReference> ( + list => list.Add ("coucou")); + + Assert.AreEqual ("System.Void System.Collections.Generic.List`1::Add(!0)", list_add.FullName); + + var definition = list_add.Resolve (); + + Assert.IsNotNull (definition); + + Assert.AreEqual ("System.Void System.Collections.Generic.List`1::Add(T)", definition.FullName); + Assert.AreEqual ("mscorlib", definition.Module.Assembly.Name.Name); + } + + [Test] + public void DictionaryOfStringTypeDefinitionTryGetValue () + { + var try_get_value = GetReference, string, bool>, MethodReference> ( + (d, s) => { + TypeDefinition type; + return d.TryGetValue (s, out type); + }); + + Assert.AreEqual ("System.Boolean System.Collections.Generic.Dictionary`2::TryGetValue(!0,!1&)", + try_get_value.FullName); + + var definition = try_get_value.Resolve (); + + Assert.IsNotNull (definition); + + Assert.AreEqual ("System.Boolean System.Collections.Generic.Dictionary`2::TryGetValue(TKey,TValue&)", definition.FullName); + Assert.AreEqual ("mscorlib", definition.Module.Assembly.Name.Name); + } + + class CustomResolver : DefaultAssemblyResolver { + + public void Register (AssemblyDefinition assembly) + { + this.RegisterAssembly (assembly); + this.AddSearchDirectory (Path.GetDirectoryName (assembly.MainModule.FullyQualifiedName)); + } + } + + [Test] + public void ExportedTypeFromModule () + { + var resolver = new CustomResolver (); + var parameters = new ReaderParameters { AssemblyResolver = resolver }; + var mma = GetResourceModule ("mma.exe", parameters); + + resolver.Register (mma.Assembly); + + var current_module = GetCurrentModule (parameters); + var reference = new TypeReference ("Module.A", "Foo", current_module, AssemblyNameReference.Parse (mma.Assembly.FullName), false); + + var definition = reference.Resolve (); + Assert.IsNotNull (definition); + Assert.AreEqual ("Module.A.Foo", definition.FullName); + } + + [Test] + public void TypeForwarder () + { + var resolver = new CustomResolver (); + var parameters = new ReaderParameters { AssemblyResolver = resolver }; + + var types = ModuleDefinition.ReadModule ( + CompilationService.CompileResource (GetCSharpResourcePath ("CustomAttributes.cs", typeof (ResolveTests).Assembly)), + parameters); + + resolver.Register (types.Assembly); + + var current_module = GetCurrentModule (parameters); + var reference = new TypeReference ("System.Diagnostics", "DebuggableAttribute", current_module, AssemblyNameReference.Parse (types.Assembly.FullName), false); + + var definition = reference.Resolve (); + Assert.IsNotNull (definition); + Assert.AreEqual ("System.Diagnostics.DebuggableAttribute", definition.FullName); + Assert.AreEqual ("mscorlib", definition.Module.Assembly.Name.Name); + } + + [Test] + public void NestedTypeForwarder () + { + var resolver = new CustomResolver (); + var parameters = new ReaderParameters { AssemblyResolver = resolver }; + + var types = ModuleDefinition.ReadModule ( + CompilationService.CompileResource (GetCSharpResourcePath ("CustomAttributes.cs", typeof (ResolveTests).Assembly)), + parameters); + + resolver.Register (types.Assembly); + + var current_module = GetCurrentModule (parameters); + var reference = new TypeReference ("", "DebuggingModes", current_module, null, true); + reference.DeclaringType = new TypeReference ("System.Diagnostics", "DebuggableAttribute", current_module, AssemblyNameReference.Parse (types.Assembly.FullName), false); + + var definition = reference.Resolve (); + Assert.IsNotNull (definition); + Assert.AreEqual ("System.Diagnostics.DebuggableAttribute/DebuggingModes", definition.FullName); + Assert.AreEqual ("mscorlib", definition.Module.Assembly.Name.Name); + } + + [Test] + public void RectangularArrayResolveGetMethod () + { + var get_a_b = GetReference, MethodReference> (matrix => matrix [2, 2]); + + Assert.AreEqual ("Get", get_a_b.Name); + Assert.IsNotNull (get_a_b.Module); + Assert.IsNull (get_a_b.Resolve ()); + } + + [Test] + public void ResolveFunctionPointer () + { + var module = GetResourceModule ("cppcli.dll"); + var global = module.GetType (""); + var field = global.GetField ("__onexitbegin_app_domain"); + + var type = field.FieldType as PointerType; + Assert.IsNotNull(type); + + var fnptr = type.ElementType as FunctionPointerType; + Assert.IsNotNull (fnptr); + + Assert.IsNull (fnptr.Resolve ()); + } + + [Test] + public void ResolveGenericParameter () + { + var collection = typeof (Mono.Collections.Generic.Collection<>).ToDefinition (); + var parameter = collection.GenericParameters [0]; + + Assert.IsNotNull (parameter); + + Assert.IsNull (parameter.Resolve ()); + } + + [Test] + public void ResolveNullVersionAssembly () + { + var reference = AssemblyNameReference.Parse ("System.Core"); + reference.Version = null; + + var resolver = new DefaultAssemblyResolver (); + Assert.IsNotNull (resolver.Resolve (reference)); + } + + static TRet GetReference (TDel code) + { + var @delegate = code as Delegate; + if (@delegate == null) + throw new InvalidOperationException (); + + var reference = (TRet) GetReturnee (GetMethodFromDelegate (@delegate)); + + Assert.IsNotNull (reference); + + return reference; + } + + static object GetReturnee (MethodDefinition method) + { + Assert.IsTrue (method.HasBody); + + var instruction = method.Body.Instructions [method.Body.Instructions.Count - 1]; + + Assert.IsNotNull (instruction); + + while (instruction != null) { + var opcode = instruction.OpCode; + switch (opcode.OperandType) { + case OperandType.InlineField: + case OperandType.InlineTok: + case OperandType.InlineType: + case OperandType.InlineMethod: + return instruction.Operand; + default: + instruction = instruction.Previous; + break; + } + } + + throw new InvalidOperationException (); + } + + static MethodDefinition GetMethodFromDelegate (Delegate @delegate) + { + var method = @delegate.Method; + var type = (TypeDefinition) TypeParser.ParseType (GetCurrentModule (), method.DeclaringType.FullName); + + Assert.IsNotNull (type); + + return type.Methods.Where (m => m.Name == method.Name).First (); + } + } +} diff --git a/Test/Mono.Cecil.Tests/SecurityDeclarationTests.cs b/Test/Mono.Cecil.Tests/SecurityDeclarationTests.cs new file mode 100644 index 000000000..5bc74e732 --- /dev/null +++ b/Test/Mono.Cecil.Tests/SecurityDeclarationTests.cs @@ -0,0 +1,199 @@ +using System; +using System.Globalization; +using System.Linq; +using System.Text; + +using Mono.Cecil; +using Mono.Cecil.Metadata; +using Mono.Cecil.PE; + +using NUnit.Framework; + +namespace Mono.Cecil.Tests { + + [TestFixture] + public class SecurityDeclarationTests : BaseTestFixture { + + [TestModule ("decsec-xml.dll")] + public void XmlSecurityDeclaration (ModuleDefinition module) + { + var type = module.GetType ("SubLibrary"); + + Assert.IsTrue (type.HasSecurityDeclarations); + + Assert.AreEqual (1, type.SecurityDeclarations.Count); + + var declaration = type.SecurityDeclarations [0]; + Assert.AreEqual (SecurityAction.Deny, declaration.Action); + + Assert.AreEqual (1, declaration.SecurityAttributes.Count); + + var attribute = declaration.SecurityAttributes [0]; + + Assert.AreEqual ("System.Security.Permissions.PermissionSetAttribute", attribute.AttributeType.FullName); + + Assert.AreEqual (1, attribute.Properties.Count); + + var named_argument = attribute.Properties [0]; + + Assert.AreEqual ("XML", named_argument.Name); + + var argument = named_argument.Argument; + + Assert.AreEqual ("System.String", argument.Type.FullName); + + const string permission_set = "\r\n\r\n\r\n"; + + Assert.AreEqual (permission_set, argument.Value); + } + + [TestModule ("decsec-att.dll")] + public void AttributeSecurityDeclaration (ModuleDefinition module) + { + var type = module.GetType ("SubLibrary"); + + Assert.IsTrue (type.HasSecurityDeclarations); + + Assert.AreEqual (1, type.SecurityDeclarations.Count); + + var declaration = type.SecurityDeclarations [0]; + Assert.AreEqual (SecurityAction.Deny, declaration.Action); + + Assert.AreEqual (1, declaration.SecurityAttributes.Count); + + var attribute = declaration.SecurityAttributes [0]; + + Assert.AreEqual ("System.Security.Permissions.SecurityPermissionAttribute", attribute.AttributeType.FullName); + + Assert.AreEqual (1, attribute.Properties.Count); + + var named_argument = attribute.Properties [0]; + + Assert.AreEqual ("UnmanagedCode", named_argument.Name); + + var argument = named_argument.Argument; + + Assert.AreEqual ("System.Boolean", argument.Type.FullName); + + Assert.AreEqual (true, argument.Value); + } + + static void AssertCustomAttributeArgument (string expected, CustomAttributeNamedArgument named_argument) + { + AssertCustomAttributeArgument (expected, named_argument.Argument); + } + + static void AssertCustomAttributeArgument (string expected, CustomAttributeArgument argument) + { + var result = new StringBuilder (); + PrettyPrint (argument, result); + + Assert.AreEqual (expected, result.ToString ()); + } + + static string PrettyPrint (CustomAttribute attribute) + { + var signature = new StringBuilder (); + signature.Append (".ctor ("); + + for (int i = 0; i < attribute.ConstructorArguments.Count; i++) { + if (i > 0) + signature.Append (", "); + + PrettyPrint (attribute.ConstructorArguments [i], signature); + } + + signature.Append (")"); + return signature.ToString (); + } + + static void PrettyPrint (CustomAttributeArgument argument, StringBuilder signature) + { + var value = argument.Value; + + signature.Append ("("); + + PrettyPrint (argument.Type, signature); + + signature.Append (":"); + + PrettyPrintValue (argument.Value, signature); + + signature.Append (")"); + } + + static void PrettyPrintValue (object value, StringBuilder signature) + { + if (value == null) { + signature.Append ("null"); + return; + } + + var arguments = value as CustomAttributeArgument []; + if (arguments != null) { + signature.Append ("{"); + for (int i = 0; i < arguments.Length; i++) { + if (i > 0) + signature.Append (", "); + + PrettyPrint (arguments [i], signature); + } + signature.Append ("}"); + + return; + } + + switch (Type.GetTypeCode (value.GetType ())) { + case TypeCode.String: + signature.AppendFormat ("\"{0}\"", value); + break; + case TypeCode.Char: + signature.AppendFormat ("'{0}'", (char) value); + break; + default: + var formattable = value as IFormattable; + if (formattable != null) { + signature.Append (formattable.ToString (null, CultureInfo.InvariantCulture)); + return; + } + + if (value is CustomAttributeArgument) { + PrettyPrint ((CustomAttributeArgument) value, signature); + return; + } + break; + } + } + + static void PrettyPrint (TypeReference type, StringBuilder signature) + { + if (type.IsArray) { + ArrayType array = (ArrayType) type; + signature.AppendFormat ("{0}[]", array.ElementType.etype.ToString ()); + } else if (type.etype == ElementType.None) { + signature.Append (type.FullName); + } else + signature.Append (type.etype.ToString ()); + } + + static void AssertArgument (T value, CustomAttributeNamedArgument named_argument) + { + AssertArgument (value, named_argument.Argument); + } + + static void AssertArgument (T value, CustomAttributeArgument argument) + { + AssertArgument (typeof (T).FullName, (object) value, argument); + } + + static void AssertArgument (string type, object value, CustomAttributeArgument argument) + { + Assert.AreEqual (type, argument.Type.FullName); + Assert.AreEqual (value, argument.Value); + } + } +} diff --git a/Test/Mono.Cecil.Tests/TypeParserTests.cs b/Test/Mono.Cecil.Tests/TypeParserTests.cs new file mode 100644 index 000000000..a367919b9 --- /dev/null +++ b/Test/Mono.Cecil.Tests/TypeParserTests.cs @@ -0,0 +1,394 @@ +using System; +using System.Linq; + +using NUnit.Framework; + +namespace Mono.Cecil.Tests { + + [TestFixture] + public class TypeParserTests : BaseTestFixture { + + [Test] + public void SimpleStringReference () + { + var module = GetCurrentModule (); + var corlib = module.TypeSystem.Corlib; + + const string fullname = "System.String"; + + var type = TypeParser.ParseType (module, fullname); + Assert.IsNotNull (type); + Assert.AreEqual (corlib, type.Scope); + Assert.AreEqual (module, type.Module); + Assert.AreEqual ("System", type.Namespace); + Assert.AreEqual ("String", type.Name); + Assert.AreEqual (MetadataType.String, type.MetadataType); + Assert.IsFalse (type.IsValueType); + Assert.IsInstanceOfType (typeof (TypeReference), type); + } + + [Test] + public void SimpleInt32Reference () + { + var module = GetCurrentModule (); + var corlib = module.TypeSystem.Corlib; + + const string fullname = "System.Int32"; + + var type = TypeParser.ParseType (module, fullname); + Assert.IsNotNull (type); + Assert.AreEqual (corlib, type.Scope); + Assert.AreEqual (module, type.Module); + Assert.AreEqual ("System", type.Namespace); + Assert.AreEqual ("Int32", type.Name); + Assert.AreEqual (MetadataType.Int32, type.MetadataType); + Assert.IsTrue (type.IsValueType); + Assert.IsInstanceOfType (typeof (TypeReference), type); + } + + [Test] + public void SimpleTypeDefinition () + { + var module = GetCurrentModule (); + + const string fullname = "Mono.Cecil.Tests.TypeParserTests"; + + var type = TypeParser.ParseType (module, fullname); + Assert.IsNotNull (type); + Assert.AreEqual (module, type.Scope); + Assert.AreEqual (module, type.Module); + Assert.AreEqual ("Mono.Cecil.Tests", type.Namespace); + Assert.AreEqual ("TypeParserTests", type.Name); + Assert.IsInstanceOfType (typeof (TypeDefinition), type); + } + + [Test] + public void ByRefTypeReference () + { + var module = GetCurrentModule (); + var corlib = module.TypeSystem.Corlib; + + const string fullname = "System.String&"; + + var type = TypeParser.ParseType (module, fullname); + + Assert.IsInstanceOfType (typeof (ByReferenceType), type); + + type = ((ByReferenceType) type).ElementType; + + Assert.IsNotNull (type); + Assert.AreEqual (corlib, type.Scope); + Assert.AreEqual (module, type.Module); + Assert.AreEqual ("System", type.Namespace); + Assert.AreEqual ("String", type.Name); + Assert.IsInstanceOfType (typeof (TypeReference), type); + } + + [Test] + public void FullyQualifiedTypeReference () + { + var module = GetCurrentModule (); + var cecil = module.AssemblyReferences.Where (reference => reference.Name == "Mono.Cecil").First (); + + var fullname = "Mono.Cecil.TypeDefinition, " + cecil.FullName; + + var type = TypeParser.ParseType (module, fullname); + Assert.IsNotNull (type); + Assert.AreEqual (cecil, type.Scope); + Assert.AreEqual (module, type.Module); + Assert.AreEqual ("Mono.Cecil", type.Namespace); + Assert.AreEqual ("TypeDefinition", type.Name); + Assert.IsInstanceOfType (typeof (TypeReference), type); + } + + [Test] + public void OpenGenericType () + { + var module = GetCurrentModule (); + var corlib = module.TypeSystem.Corlib; + + const string fullname = "System.Collections.Generic.Dictionary`2"; + + var type = TypeParser.ParseType (module, fullname); + Assert.IsNotNull (type); + Assert.AreEqual (corlib, type.Scope); + Assert.AreEqual (module, type.Module); + Assert.AreEqual ("System.Collections.Generic", type.Namespace); + Assert.AreEqual ("Dictionary`2", type.Name); + Assert.IsInstanceOfType (typeof (TypeReference), type); + Assert.AreEqual (2, type.GenericParameters.Count); + } + + public class ID {} + + [Test] + public void SimpleNestedType () + { + var module = GetCurrentModule (); + + const string fullname = "Mono.Cecil.Tests.TypeParserTests+ID"; + + var type = TypeParser.ParseType (module, fullname); + + Assert.IsNotNull (type); + Assert.AreEqual (module, type.Module); + Assert.AreEqual (module, type.Scope); + Assert.AreEqual ("", type.Namespace); + Assert.AreEqual ("ID", type.Name); + + Assert.AreEqual ("Mono.Cecil.Tests.TypeParserTests/ID", type.FullName); + Assert.AreEqual (fullname, TypeParser.ToParseable (type)); + } + + [Test] + public void TripleNestedTypeWithScope () + { + var module = GetCurrentModule (); + + const string fullname = "Bingo.Foo`1+Bar`1+Baz`1, Bingo"; + + var type = TypeParser.ParseType (module, fullname); + + Assert.AreEqual ("Bingo.Foo`1+Bar`1+Baz`1, Bingo, Culture=neutral, PublicKeyToken=null", TypeParser.ToParseable (type)); + + Assert.IsNotNull (type); + Assert.AreEqual ("Bingo", type.Scope.Name); + Assert.AreEqual (module, type.Module); + Assert.AreEqual ("", type.Namespace); + Assert.AreEqual ("Baz`1", type.Name); + Assert.IsInstanceOfType (typeof (TypeReference), type); + Assert.AreEqual (1, type.GenericParameters.Count); + + type = type.DeclaringType; + + Assert.IsNotNull (type); + Assert.AreEqual ("Bingo", type.Scope.Name); + Assert.AreEqual (module, type.Module); + Assert.AreEqual ("", type.Namespace); + Assert.AreEqual ("Bar`1", type.Name); + Assert.IsInstanceOfType (typeof (TypeReference), type); + Assert.AreEqual (1, type.GenericParameters.Count); + + type = type.DeclaringType; + + Assert.IsNotNull (type); + Assert.AreEqual ("Bingo", type.Scope.Name); + Assert.AreEqual (module, type.Module); + Assert.AreEqual ("Bingo", type.Namespace); + Assert.AreEqual ("Foo`1", type.Name); + Assert.IsInstanceOfType (typeof (TypeReference), type); + Assert.AreEqual (1, type.GenericParameters.Count); + } + + [Test] + public void Vector () + { + var module = GetCurrentModule (); + + const string fullname = "Bingo.Gazonk[], Bingo"; + + var type = TypeParser.ParseType (module, fullname); + + Assert.AreEqual ("Bingo.Gazonk[], Bingo, Culture=neutral, PublicKeyToken=null", TypeParser.ToParseable (type)); + + var array = type as ArrayType; + Assert.IsNotNull (array); + Assert.AreEqual (1, array.Rank); + Assert.IsTrue (array.IsVector); + + type = array.ElementType; + + Assert.IsNotNull (type); + Assert.AreEqual ("Bingo", type.Scope.Name); + Assert.AreEqual (module, type.Module); + Assert.AreEqual ("Bingo", type.Namespace); + Assert.AreEqual ("Gazonk", type.Name); + Assert.IsInstanceOfType (typeof (TypeReference), type); + } + + [Test] + public void ThreeDimensionalArray () + { + var module = GetCurrentModule (); + + const string fullname = "Bingo.Gazonk[,,], Bingo"; + + var type = TypeParser.ParseType (module, fullname); + + var array = type as ArrayType; + Assert.IsNotNull (array); + Assert.AreEqual (3, array.Rank); + Assert.IsFalse (array.IsVector); + + type = array.ElementType; + + Assert.IsNotNull (type); + Assert.AreEqual ("Bingo", type.Scope.Name); + Assert.AreEqual (module, type.Module); + Assert.AreEqual ("Bingo", type.Namespace); + Assert.AreEqual ("Gazonk", type.Name); + Assert.IsInstanceOfType (typeof (TypeReference), type); + } + + [Test] + public void GenericInstanceExternArguments () + { + var module = GetCurrentModule (); + + var fullname = string.Format ("System.Collections.Generic.Dictionary`2[[System.Int32, {0}],[System.String, {0}]]", + typeof (object).Assembly.FullName); + + var type = TypeParser.ParseType (module, fullname); + + Assert.AreEqual (fullname, TypeParser.ToParseable (type)); + + var instance = type as GenericInstanceType; + Assert.IsNotNull (instance); + Assert.AreEqual (2, instance.GenericArguments.Count); + Assert.AreEqual ("mscorlib", type.Scope.Name); + Assert.AreEqual (module, type.Module); + Assert.AreEqual ("System.Collections.Generic", type.Namespace); + Assert.AreEqual ("Dictionary`2", type.Name); + + type = instance.ElementType; + + Assert.AreEqual (2, type.GenericParameters.Count); + + var argument = instance.GenericArguments [0]; + Assert.AreEqual ("mscorlib", argument.Scope.Name); + Assert.AreEqual (module, argument.Module); + Assert.AreEqual ("System", argument.Namespace); + Assert.AreEqual ("Int32", argument.Name); + + argument = instance.GenericArguments [1]; + Assert.AreEqual ("mscorlib", argument.Scope.Name); + Assert.AreEqual (module, argument.Module); + Assert.AreEqual ("System", argument.Namespace); + Assert.AreEqual ("String", argument.Name); + } + + [Test] + public void GenericInstanceMixedArguments () + { + var module = GetCurrentModule (); + + var fullname = string.Format ("System.Collections.Generic.Dictionary`2[Mono.Cecil.Tests.TypeParserTests,[System.String, {0}]]", + typeof (object).Assembly.FullName); + + var type = TypeParser.ParseType (module, fullname); + + var instance = type as GenericInstanceType; + Assert.IsNotNull (instance); + Assert.AreEqual (2, instance.GenericArguments.Count); + Assert.AreEqual ("mscorlib", type.Scope.Name); + Assert.AreEqual (module, type.Module); + Assert.AreEqual ("System.Collections.Generic", type.Namespace); + Assert.AreEqual ("Dictionary`2", type.Name); + + type = instance.ElementType; + + Assert.AreEqual (2, type.GenericParameters.Count); + + var argument = instance.GenericArguments [0]; + Assert.IsInstanceOfType (typeof (TypeDefinition), argument); + Assert.AreEqual (module, argument.Module); + Assert.AreEqual ("Mono.Cecil.Tests", argument.Namespace); + Assert.AreEqual ("TypeParserTests", argument.Name); + + argument = instance.GenericArguments [1]; + Assert.AreEqual ("mscorlib", argument.Scope.Name); + Assert.AreEqual (module, argument.Module); + Assert.AreEqual ("System", argument.Namespace); + Assert.AreEqual ("String", argument.Name); + } + + public class Foo { + } + + public class Bar {} + + [Test] + public void GenericInstanceTwoNonFqArguments () + { + var module = GetCurrentModule (); + + var fullname = string.Format ("System.Collections.Generic.Dictionary`2[Mono.Cecil.Tests.TypeParserTests+Bar,Mono.Cecil.Tests.TypeParserTests+Bar], {0}", typeof (object).Assembly.FullName); + + var type = TypeParser.ParseType (module, fullname); + + var instance = type as GenericInstanceType; + Assert.IsNotNull (instance); + Assert.AreEqual (2, instance.GenericArguments.Count); + Assert.AreEqual ("mscorlib", type.Scope.Name); + Assert.AreEqual (module, type.Module); + Assert.AreEqual ("System.Collections.Generic", type.Namespace); + Assert.AreEqual ("Dictionary`2", type.Name); + + type = instance.ElementType; + + Assert.AreEqual (2, type.GenericParameters.Count); + + var argument = instance.GenericArguments [0]; + Assert.AreEqual (module, argument.Module); + Assert.AreEqual ("", argument.Namespace); + Assert.AreEqual ("Bar", argument.Name); + Assert.IsInstanceOfType (typeof (TypeDefinition), argument); + + argument = instance.GenericArguments [1]; + Assert.AreEqual (module, argument.Module); + Assert.AreEqual ("", argument.Namespace); + Assert.AreEqual ("Bar", argument.Name); + Assert.IsInstanceOfType (typeof (TypeDefinition), argument); + } + + [Test] + public void ComplexGenericInstanceMixedArguments () + { + var module = GetCurrentModule (); + + var fullname = string.Format ("System.Collections.Generic.Dictionary`2[[System.String, {0}],Mono.Cecil.Tests.TypeParserTests+Foo`2[Mono.Cecil.Tests.TypeParserTests,[System.Int32, {0}]]]", + typeof (object).Assembly.FullName); + + var type = TypeParser.ParseType (module, fullname); + + var instance = type as GenericInstanceType; + Assert.IsNotNull (instance); + Assert.AreEqual (2, instance.GenericArguments.Count); + Assert.AreEqual ("mscorlib", type.Scope.Name); + Assert.AreEqual (module, type.Module); + Assert.AreEqual ("System.Collections.Generic", type.Namespace); + Assert.AreEqual ("Dictionary`2", type.Name); + + type = instance.ElementType; + + Assert.AreEqual (2, type.GenericParameters.Count); + + var argument = instance.GenericArguments [0]; + Assert.AreEqual ("mscorlib", argument.Scope.Name); + Assert.AreEqual (module, argument.Module); + Assert.AreEqual ("System", argument.Namespace); + Assert.AreEqual ("String", argument.Name); + + argument = instance.GenericArguments [1]; + + instance = argument as GenericInstanceType; + Assert.IsNotNull (instance); + Assert.AreEqual (2, instance.GenericArguments.Count); + Assert.AreEqual (module, instance.Module); + Assert.AreEqual ("Mono.Cecil.Tests.TypeParserTests/Foo`2", instance.ElementType.FullName); + Assert.IsInstanceOfType (typeof (TypeDefinition), instance.ElementType); + + argument = instance.GenericArguments [0]; + Assert.AreEqual (module, argument.Module); + Assert.AreEqual ("Mono.Cecil.Tests", argument.Namespace); + Assert.AreEqual ("TypeParserTests", argument.Name); + Assert.IsInstanceOfType (typeof (TypeDefinition), argument); + + argument = instance.GenericArguments [1]; + Assert.AreEqual ("mscorlib", argument.Scope.Name); + Assert.AreEqual (module, argument.Module); + Assert.AreEqual ("System", argument.Namespace); + Assert.AreEqual ("Int32", argument.Name); + } + } +} diff --git a/Test/Mono.Cecil.Tests/TypeTests.cs b/Test/Mono.Cecil.Tests/TypeTests.cs new file mode 100644 index 000000000..f6b925ee7 --- /dev/null +++ b/Test/Mono.Cecil.Tests/TypeTests.cs @@ -0,0 +1,171 @@ +using System; +using System.Linq; + +using Mono.Cecil; +using Mono.Cecil.Cil; +using Mono.Cecil.Metadata; + +using NUnit.Framework; + +namespace Mono.Cecil.Tests { + + [TestFixture] + public class TypeTests : BaseTestFixture { + + [TestCSharp ("Layouts.cs")] + public void TypeLayout (ModuleDefinition module) + { + var foo = module.GetType ("Foo"); + Assert.IsNotNull (foo); + Assert.IsTrue (foo.IsValueType); + + Assert.IsTrue (foo.HasLayoutInfo); + Assert.AreEqual (16, foo.ClassSize); + + var babar = module.GetType ("Babar"); + Assert.IsNotNull (babar); + Assert.IsFalse (babar.IsValueType); + Assert.IsFalse (babar.HasLayoutInfo); + } + + [TestIL ("types.il")] + public void SimpleInterfaces (ModuleDefinition module) + { + var ibaz = module.GetType ("IBaz"); + Assert.IsNotNull (ibaz); + + Assert.IsTrue (ibaz.HasInterfaces); + + var interfaces = ibaz.Interfaces; + + Assert.AreEqual (2, interfaces.Count); + + Assert.AreEqual ("IBar", interfaces [0].FullName); + Assert.AreEqual ("IFoo", interfaces [1].FullName); + } + + [TestCSharp ("Generics.cs")] + public void GenericTypeDefinition (ModuleDefinition module) + { + var foo = module.GetType ("Foo`2"); + Assert.IsNotNull (foo); + + Assert.IsTrue (foo.HasGenericParameters); + Assert.AreEqual (2, foo.GenericParameters.Count); + + var tbar = foo.GenericParameters [0]; + + Assert.AreEqual ("TBar", tbar.Name); + Assert.AreEqual (foo, tbar.Owner); + + var tbaz = foo.GenericParameters [1]; + + Assert.AreEqual ("TBaz", tbaz.Name); + Assert.AreEqual (foo, tbaz.Owner); + } + + [TestCSharp ("Generics.cs")] + public void ConstrainedGenericType (ModuleDefinition module) + { + var bongo_t = module.GetType ("Bongo`1"); + Assert.IsNotNull (bongo_t); + + var t = bongo_t.GenericParameters [0]; + Assert.IsNotNull (t); + Assert.AreEqual ("T", t.Name); + + Assert.IsTrue (t.HasConstraints); + Assert.AreEqual (2, t.Constraints.Count); + + Assert.AreEqual ("Zap", t.Constraints [0].FullName); + Assert.AreEqual ("IZoom", t.Constraints [1].FullName); + } + + [TestCSharp ("Generics.cs")] + public void GenericBaseType (ModuleDefinition module) + { + var child = module.GetType ("Child`1"); + + var child_t = child.GenericParameters [0]; + Assert.IsNotNull (child_t); + + var instance = child.BaseType as GenericInstanceType; + Assert.IsNotNull (instance); + Assert.AreNotEqual (0, instance.MetadataToken.RID); + + Assert.AreEqual (child_t, instance.GenericArguments [0]); + } + + [TestCSharp ("Generics.cs")] + public void GenericConstraintOnGenericParameter (ModuleDefinition module) + { + var duel = module.GetType ("Duel`3"); + + Assert.AreEqual (3, duel.GenericParameters.Count); + + var t1 = duel.GenericParameters [0]; + var t2 = duel.GenericParameters [1]; + var t3 = duel.GenericParameters [2]; + + Assert.AreEqual (t1, t2.Constraints [0]); + Assert.AreEqual (t2, t3.Constraints [0]); + } + + [TestCSharp ("Generics.cs")] + public void GenericForwardBaseType (ModuleDefinition module) + { + var tamchild = module.GetType ("TamChild"); + + Assert.IsNotNull (tamchild); + Assert.IsNotNull (tamchild.BaseType); + + var generic_instance = tamchild.BaseType as GenericInstanceType; + + Assert.IsNotNull (generic_instance); + + Assert.AreEqual (1, generic_instance.GenericArguments.Count); + Assert.AreEqual (module.GetType ("Tamtam"), generic_instance.GenericArguments [0]); + } + + [TestCSharp ("Generics.cs")] + public void TypeExtentingGenericOfSelf (ModuleDefinition module) + { + var rec_child = module.GetType ("RecChild"); + + Assert.IsNotNull (rec_child); + Assert.IsNotNull (rec_child.BaseType); + + var generic_instance = rec_child.BaseType as GenericInstanceType; + + Assert.IsNotNull (generic_instance); + + Assert.AreEqual (1, generic_instance.GenericArguments.Count); + Assert.AreEqual (rec_child, generic_instance.GenericArguments [0]); + } + + [TestCSharp ("Methods.cs")] + public void TypeReferenceValueType (ModuleDefinition module) + { + var baz = module.GetType ("Baz"); + var method = baz.GetMethod ("PrintAnswer"); + + var box = method.Body.Instructions.Where (i => i.OpCode == OpCodes.Box).First (); + var int32 = (TypeReference) box.Operand; + + Assert.IsTrue (int32.IsValueType); + } + + [TestModule ("gifaceref.exe")] + public void GenericInterfaceReference (ModuleDefinition module) + { + var type = module.GetType ("Program"); + var iface = type.Interfaces [0]; + + var instance = (GenericInstanceType) iface; + var owner = instance.ElementType; + + Assert.AreEqual (1, instance.GenericArguments.Count); + Assert.AreEqual (1, owner.GenericParameters.Count); + } + } +} diff --git a/Test/Mono.Cecil.Tests/VariableTests.cs b/Test/Mono.Cecil.Tests/VariableTests.cs new file mode 100644 index 000000000..9f6c54c67 --- /dev/null +++ b/Test/Mono.Cecil.Tests/VariableTests.cs @@ -0,0 +1,108 @@ +using System; +using System.Linq; + +using Mono.Cecil; +using Mono.Cecil.Cil; + +using NUnit.Framework; + +namespace Mono.Cecil.Tests { + + [TestFixture] + public class VariableTests : BaseTestFixture { + + [Test] + public void AddVariableIndex () + { + var object_ref = new TypeReference ("System", "Object", null, null, false); + var method = new MethodDefinition ("foo", MethodAttributes.Static, object_ref); + var body = new MethodBody (method); + + var x = new VariableDefinition ("x", object_ref); + var y = new VariableDefinition ("y", object_ref); + + body.Variables.Add (x); + body.Variables.Add (y); + + Assert.AreEqual (0, x.Index); + Assert.AreEqual (1, y.Index); + } + + [Test] + public void RemoveAtVariableIndex () + { + var object_ref = new TypeReference ("System", "Object", null, null, false); + var method = new MethodDefinition ("foo", MethodAttributes.Static, object_ref); + var body = new MethodBody (method); + + var x = new VariableDefinition ("x", object_ref); + var y = new VariableDefinition ("y", object_ref); + var z = new VariableDefinition ("z", object_ref); + + body.Variables.Add (x); + body.Variables.Add (y); + body.Variables.Add (z); + + Assert.AreEqual (0, x.Index); + Assert.AreEqual (1, y.Index); + Assert.AreEqual (2, z.Index); + + body.Variables.RemoveAt (1); + + Assert.AreEqual (0, x.Index); + Assert.AreEqual (-1, y.Index); + Assert.AreEqual (1, z.Index); + } + + [Test] + public void RemoveVariableIndex () + { + var object_ref = new TypeReference ("System", "Object", null, null, false); + var method = new MethodDefinition ("foo", MethodAttributes.Static, object_ref); + var body = new MethodBody (method); + + var x = new VariableDefinition ("x", object_ref); + var y = new VariableDefinition ("y", object_ref); + var z = new VariableDefinition ("z", object_ref); + + body.Variables.Add (x); + body.Variables.Add (y); + body.Variables.Add (z); + + Assert.AreEqual (0, x.Index); + Assert.AreEqual (1, y.Index); + Assert.AreEqual (2, z.Index); + + body.Variables.Remove (y); + + Assert.AreEqual (0, x.Index); + Assert.AreEqual (-1, y.Index); + Assert.AreEqual (1, z.Index); + } + + [Test] + public void InsertVariableIndex () + { + var object_ref = new TypeReference ("System", "Object", null, null, false); + var method = new MethodDefinition ("foo", MethodAttributes.Static, object_ref); + var body = new MethodBody (method); + + var x = new VariableDefinition ("x", object_ref); + var y = new VariableDefinition ("y", object_ref); + var z = new VariableDefinition ("z", object_ref); + + body.Variables.Add (x); + body.Variables.Add (z); + + Assert.AreEqual (0, x.Index); + Assert.AreEqual (-1, y.Index); + Assert.AreEqual (1, z.Index); + + body.Variables.Insert (1, y); + + Assert.AreEqual (0, x.Index); + Assert.AreEqual (1, y.Index); + Assert.AreEqual (2, z.Index); + } + } +} diff --git a/Test/Resources/assemblies/boxedoptarg.dll b/Test/Resources/assemblies/boxedoptarg.dll new file mode 100644 index 0000000000000000000000000000000000000000..23edd61bb885effcb95ae501ed93d10716729b94 GIT binary patch literal 3072 zcmeHJ&2Jk;6#uR3L~fu_P^FLx5+-$ms)81y_&^1sZa&%uk|xA%8da5=wY@lt);rej zx;Qxm4obKcEsvBo2h%n_b6tRne;I0inL+eZP70-kX_C zR&U@B*(GhS!E>JS`-^m``qi_8*iu)%Irw^=^!|BS77pYdL8==!wH75vktg5aG z+kx@|wYXMROR8|($woqz>0MOfBy2|)9!8$k(qwQ$|Xe&C)TMvxgwT`LKImh z387@_7mht5?E)E;z6Qq3Z;z*H5`tgP0yji10sHB?)RnMp;MD=cGb##T2gi`3e)U)b z?AYzZ)MsS)^qB@8+n?rbJB-2_-KMru8kf$5nt>9lw?o(03^cWF(=540h<#83=KIt{ zl(`b5whV@FO94AvYl-nWU@CKtOGnNRpXX-fPv)&Olhk#mXcz3c!rc28B=Hb@(nrMn zSHKom?TcKFLoaAV6p>>cGQ<4!GR7$LB$2;zeR+{wQJ0$Y^S-W<3(#a;nFLOX^4IJf z#*;o|#Pk`IzC;%;HsON64=EqU6kf+L%9taKNClD@=|-f}#33WED~cGNnB}l7Y#D7F z?_iYL*qDX)SdI8zBb~q*Bj>pGG;HD|=^J<(**!c4-%^)1*#)crFh5$=^|tSRjAm5R zq3>03S!QFWd)}(^uA5v%}vf zSH5q4_~63Li@zcF>q!3 zUzahYkM_nBGTk#V1$2Lks8R;rWkuF;{33UcP&0X21N$h(7I=$$v73wy8QrU;z%M`# zff7%^GTp=`Hel^O=jEVD9jrj3L#a+KyU7e1%u#2QJhpSDwiQM+%*q85w`;0vV23MU zp2t&&BBLz{Dmc`}1t_WF}vfe*}@OPoW*$R>O8vCFES cwvJ0*!i%1OO8#e1$)C9wo&9CL|M&#{0YH8KWdHyG literal 0 HcmV?d00001 diff --git a/Test/Resources/assemblies/catch.exe b/Test/Resources/assemblies/catch.exe new file mode 100644 index 0000000000000000000000000000000000000000..d7ef04afb22c37d1d9c7b15929a40e012140d921 GIT binary patch literal 3584 zcmeHJ&uL1wszk!GQ)PB#J{&t4Oe3Pn@N@JMPTd zbvRVHv{I{9qIW8B>o|^}4N^}PFPS&*y?O7= z_hx2aGX35S>LH?DjHgeD?qJqbF#Mm{Dwg}-xZ6+PZhJUz$C`RLFu&|6R+pkCoq)Mc z7>bBhIFpT#c_Ay!lvyCE+}^pf?@*F@c7kZi>Y<0l#S87-9#hKNZe?Onm^9rV1Y;Nl z49ys(RO|xD;MX&)V!*DchYBAP?KZ!iIZ(}%E;t`hCoXxog=h!W_= zI|Kclb#ZpYTM_i1_2Fa96p-MCW{448wWX3SG=r@GA)O3NZ7Kl0Ex9k?Xs}+ziq5qG zIQ+(8?V?+#Uz5g`qAm0bBf5!L3p$40?S*K2&Z40tVhDNCkJ3Xp*7Wa>cE34j-aseg>fr(H)S`E z+d2E~+==5SbcQYDgYQ7L!HUe_A87HwFuw=IHedXhzmWm_n#8nbY(Z9Y!J7=mPj>hTk@p z2jH4w|G1*vgpE*x)@GSr{gOsZt~-f#(r9-REpN0R60Kmg`$qd@e~J2$d%lTVe?XSid5_Tq;(Mxbi-K4*53t1hK$m5|$aO4bWiG*=HL^^67 zs}8IR>kdWm6VPJ%ruQb2TEG;+%Y(i4j7+-USd?4)8KnwjLJvs6-rl){-4(eePrYj& z2HzasTE}+*z7pOYEIE9;ok28ezIt6vWPC$l_iu?-nKQ;=)M z`z$K0(~3b1)S+wA?@-rX zM7;{00Zz{cD)z5&2&E_Ye#)O|1wLzXsqn#%WsljpEaRaos_6Y=*-P{1j-Jdi6**zm z@kPkTvMXF=&z#=bmv@xnLB(HTND!*AY(s{pl)KCWM;#43R|+MTqNA<|PB|*Do5!*& za6)g1t7u{UZb-%0TC&M18W4I@7b5(z0;JH(v0nE*bS&Vtoq9bx9A}7RLq(I} zlGr4k<5?4jy%l#G5_={(ERuiF08U<=m0lBlw#L;avyQa0GEgTET9n(+h^Kgy`^?vT zEbFMruqoc>GRqoX(M2D}F)lg2;z>~^$?!AKw4o1oVb2e*9ReKk!|fY_qHp^pz3>UJ S_}|0_BQG5JGT?u30)GRb5V>#w literal 0 HcmV?d00001 diff --git a/Test/Resources/assemblies/cppcli.dll b/Test/Resources/assemblies/cppcli.dll new file mode 100644 index 0000000000000000000000000000000000000000..f216fde980cbdbb8194a82cd151c07dad8c7cc2e GIT binary patch literal 50176 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 literal 0 HcmV?d00001 diff --git a/Test/Resources/assemblies/gifaceref.exe b/Test/Resources/assemblies/gifaceref.exe new file mode 100644 index 0000000000000000000000000000000000000000..c8e2ed12315baaa9bf645032bb2d111de1cba5f5 GIT binary patch literal 5120 zcmeHK-ESOM6+d%#v%6k9CUN3?l+cXVi7<9EUdNV5!`fLp>!b^|hgQG~eIWeKomubN zxJmj7x$ArGIrpBA-#K???)ChQS1CqBarB1|iQd4-EwAXK$u^dIPyecy?smO1@P;<` z&cO1zerGZ?r{4T0$Bd2}W^1`*;0r||Pg+vu3*7Nh+4i4Lj1_85tw3Vrl>A{97K z^d1*sZ@WpHBC^^jWxQ+*~PGSfF6Uq-FJsY|jrkSNL&uFSjVa+!tjI1%99UprhhOo3jzlQ_| zzf1HH#-ngQxD_`Z53Vdx4|v8tcy*;%z<3JsYb?*$ZW$vtxX@lY{(5&8 z82b3^I2{Z3h;hQT>c~VP0&ayriII6Epi0lCaIJWrYjuA3nCI0IIs-aS=RqC%D(G#+ z|3vX0(+8M&Mq~P-#+ttqzZ41jyq7ILo|s+mbkBJ z6QI3f0v-yYK>yU){Lk9UsEI~L2Uz-p_Bx$_^qi7@Oz+a?AdM>N2PfXA0Z5B_sQGm* z3+d;f)a7emg!E>#_Ljz)zm257De3J<^Q6dQ?T<=gpJyR)je3OuGC>DX<1~6d`T(7z zmw{-ESnqkz0r~=QEnhFDlxlsHv!d%G@G@K8re6@LQp` z@I6|g2a4(%^La%V=>~m+%6PJ33fY3-clH%A2W$z<3F<;U1)k~{em!_&7;hJ7ufl$a zJ_EiFk2JqA@ogCIY8Q}h=Lb*&CT{E*EjRC0o3@;yK>C3pHzh5G-+8M071y(^GA(WS zfvnTD@;7BAh$Q2(YugYl*YS<3(vhB3q2jF5tV_=<+w$hvK8l?RJAB}JP`)aI$QW|x z+CFZKjyQ_HEL(a@(%Y~q(x-637ks+&LschL+u+?7WYEf=i@TqF4l%-<9@*A$tHK2KSLoV=nkefPRDpi`EC!I$X za3?X~&qer)PB4Cc%BabpbUAX+$wyk9yV0r+oEX=oF9Ql`%V8U!5wen6V{U4!RPqB8 z=|9GCCx+bAM5z?uim;zi^lUsLwN_e>iMU6tV3{??^#iNoQ$d!SwVL!^u&Pz*v^QzN z4VIdXhU*2gI=fks4c=^06^*uEdI}#BuC~o6rt_OY_wW5B@$lC-uKe`=>3e6h{zFRL zyZyD*lM@eqc%Z+pOG_nn>hC+OrQ$mE_2Xl$!A^_onwG*k<{=7^;DJ?+u-j9yL|-a4 zMBGoslR~88{56Utp`FxDbtOe#Pv|qL_4TK;=$iB_e_)rzv6novvEVv8xh$`H?zesR za3VVI8Mnc_&fI^u*1dqJblLT0H>G-G)T=I~QMLJe!;SGQ>3PLHCI1T*5b7SH6K$VB zIu|hR&Wax|qQy^`U*Bh*?YEiiYV3vRRrH_bakL1Q!uDW>=&#|jn#kc^K(tCrR05r) z>)?uXjTRsmL9c-4c0c~%zxlM@+b%^De6sCbEvUIwGRcD<3n#0DPlwjXRaR$+t(LKB zV%EpHNdfd+NMZX${53e$fGL2Mh56b(o;Ht%aOhXco-%rrgcqF-5;b<;mrw<@0NyKBL@id(;E z`gLPtETh*=$6CXYzuFlMu5^9JSrJE1fIGr2MEK_cs2sD7@bg>KjfQPi)J4NE8;#6p z=ppc$eo%DQ+$Y3yKBMdq+n2ahAZ8?E#*??2z$vSXp0$DdPEGnx=ykm1RYz<4!4Xku z^0_%DH>9oGOeZs@UvxIyZ%HqsH?8Rk?o%k^nrZtoN=i8y-3Ltz`sgm~xzU{>Kp{8U b+93$M+fUo4u7Do?ub9Wj{%QOFtH6H%HU-QJ literal 0 HcmV?d00001 diff --git a/Test/Resources/assemblies/hello.anycpu.exe b/Test/Resources/assemblies/hello.anycpu.exe new file mode 100644 index 0000000000000000000000000000000000000000..44ef8db84c0d42a418b1ad6dcf4cd46be22c58d5 GIT binary patch literal 3584 zcmeHJ&vO(-6n?W=s1PItN+F1aoe5M?luQ;9g`yI&AqlvckS#U|RTd@8&UUhcGt*=D z?7HiL$_1;u;mxBz&Q@`-N=mUj=r#X=2M(URz}d3IuX|?MO^6z=%G>no_g=q#{k=ES zZ!-VRUFsvEJjRnJME5akDjNRxYz@nUuYEg6U+-EUx^K;`4=vVx#bPN|r5iHOjUth- zDrd40F+XB63l$cM8h7^W8917SF3%FpS$%Yi|6b~x_K2=9~JKq?KOYhIa5;?`q?I0&~lOJu`a@9x=HlHX4`gjMwCG}-u=+u z>e=Tcyp=#7)5XV{Ng%@w%@8BH=}09#Xa-vm!p>}9>QE8r9mxX$M}zeyR&=aQz~OfR z)(x~**A=9(Ei6gn=sOi8799+44!7@=(Sk2Q; z!Fi)_=JXjIeg_5MzhDgCCMqMsPg<@d(vMaZMA{EbI-TLA3Ngrdsx*9QsWgMR0A0_+ z7XnemtO+LT(te^{TKUZyr2}bB`E<>crz2;%Vr3vhxRXZdbtKPe7W|Ik_h8Yay*1bK zUOEiE!)Rp&kv^ewCd#`;`{>{#4Ptd4P11{W2z-!+aK~N-E-gE>n_dNfiH=czjW*Gj z(2>VevM764+A=;bYK?%Or#cS;;kZ%TiyIDaaVn?xk3!`M8TeJIv{k}GTBzRQUPAM( zACcoFLS_rj)kc)~A$O)l82bU26)u~;#}%apH}OSul?QIiNNOs z_({9F+6xS!A|(P&*QB5DIX~h$hg~Zq@Ed~o`TU{V>t7tceD}v!zPk4I<9pQq&4<^Q z4~;$i7;lo*$H>Yv%j(aQWexUQ+0{CtpTc79z%}W{S41@1@_4MlF4m>^Kw0^oavjk! z!`Om4cOYH5F)ie5i<>f;5_0a;0{woXLmnemG}3>Q<;=Ze=%NRa;MugB_N1D=_2s{? z*SE0i&1*doQZc$x$^%T%Eo;IniUQVAXV3iJ~A#k70V z_xVSEbnd3vn6b%h)_1)ptg+4*+cLQ%5ywXl;)ofMek(N{CB17At1hex>nh0uxW-~oOD`*e0~oE%dF8mE@=AUbaF%|Tl=yQkqD z!&7IviU|7qrLoPKvlcSDu7W+l+D?8^VB)(_f*$r3iVLH z8lt)ZP_lpAhpqJJyC23UTVcSOTq?AV3Hy{&uo;g$QNy=q!d_auc=D{xRN_W8HxLn@ zu-jbOljrvgjJrzluo|=(0z_)UZpi4I^6ETv)ydHJq)=idIq8Y;oU1~odCF#?8~H0- zCCk01ArxazgOzF=?Ko*~K!lGaP(^NtBf#5$M#4XA(0K0l%f@}O+2S< zvkzx0?lsVu+nElFG9?4<8+ram5W3&yq4hMz%oHfj+VU`}oMyBEVsMr1ONJ=%@Xho~Zy!|F0^H MKC|-N@IR=)pMJ)$UH||9 literal 0 HcmV?d00001 diff --git a/Test/Resources/assemblies/hello.exe b/Test/Resources/assemblies/hello.exe new file mode 100644 index 0000000000000000000000000000000000000000..efd7c7da9bd1e4cedb3d50b2d1c963352f2fb4b0 GIT binary patch literal 3584 zcmeHJO>7%Q6n^VCRhkm3(5kc&Dw9nsszNtz5@=L8sq@a_<3gLYz2MqT)v!I9EdA${`0%2&s1tly7F&aS~c+uT@_=Z{BJh7zu6X+bFY4vqq_(158ksD?+>ole8uWgY)Us|o*P9X zW);q4BVvBUW|zw>6jkmF4D_E$Q1wlr5Ypp1hE!$487Y^(OV=DRzHKX`swV+%o&_%|5n2XT$ zJTx7M3T90(S(lFz9n{KS)+ilIY62X+W=2O&YlXExMR)*voksE3X%hUF;a|d{NqcLq z=fi|8fL?1Q29Z9eQIqAm(LOysPC2Z-NaOSpodD0#Abm|Q1DBQ^Iz+F4A3^Ty7VV=u z&^6W$S@7MV!jh;q0zOGK9t6VSEl#E6;ZdkOAp^fc<+h4>NXwP?xfj!t>qq2xv5@J4 zv(kuSKjhAg2 zxr)Mpl+tR$rDZE7xbGPwk}s4y&1C*Q8s&Dx$fT$LqR=)tVF^ zDeGu@*YyUDmYJ6RO`SK9tlXFpa<0YA>6w$|+^GiozM^BECRQ}kv%xavT`_dg<0xo6 z>886%OKyGXG4|Rc>^gXBSB6Bi%yb+4iy~2B*CpScCi){;Ha>;S80K{<(+%)BT7k5H zj(rvS0{DE=z3Ip7gTFg((*&mMQabCmzALS<&Klb~xww1t<|cCFjA#S5QPU~XQL9*W zVO6-FF2(Q@&=UG4dk0A^V2a`8!@l{5OfBP+r_R4IszBELEQ8q2&a-$A3NJ$Esqfi` z!8ea9-t}FFuY`9OOCDXMJBY?i7t+u7AlgJkj5v*@U~(^~c3rj3-Kj%skKbd=)KNmLz-w=y-WcC?Z#CUIbWQpm>e{DJ zuYzZY(+hx#{cjvX>B09u6)v^HfHk>PXay7Yc_(i(9(kgQ-~1l z&xmc}u(#q~18umS>aa-uVFNgMwIux}djBR@PndPIla+zGdC(%ghHkctyvYL=Xg*=P zY9VTh54f~h!=Li-+k#`#DaXW#_>0Rw8Mt^fc4 literal 0 HcmV?d00001 diff --git a/Test/Resources/assemblies/hello.ia64.exe b/Test/Resources/assemblies/hello.ia64.exe new file mode 100644 index 0000000000000000000000000000000000000000..1d50f54d8bd706751503aac96a8e40ac6216699e GIT binary patch literal 3072 zcmeHI&u<$=6n^VCRhp8hl&Z86Dw9n>p&}bM4YVprn8OOQ5yfpkBM$$RFc*D-_Q-y2%5xRO;vQ4VdNId%|; zh!r^tYXNfuwy;`Yz9?~PV4!~_fzB_&NTui&|1+0_=nDa7>ZD4wZ)I(IfTiXQf#!$O5O<_wJ<)2L5a8S9nI#fggwxR*TW2lx+v zOq2)0Ps%Ptp&OJXOgaf}ivI9Mff#Icio;hoatjzU@YOgx=ZPXlB?uW;PZAwf&L74F zIu-9N9p_ZO-Qr}=i1a56kI*EIp$R**1bsv6ZxB(Us+Csbae5BAS9^H|lRl@{G|D^L zyKy>8gUCKjSvo;ypa*G)?$EQ~rEH6i0l}hY=mkpe(mweLzT(*ugGO2=(bS44)jWQM zD%|sgm5c1at@##jaLUIoAo3C0x3LB*F!hr z%WlANI6EZp8^W$0eDc!o_kVtI<%??R?cmL|U#aiAkG3|?O#bp2o+P7(k&$MG(U&H} z80<3$mjmRiI)(Mrsq3L#y(WUihQq6h>v|;=AIkWkbm0?qxDKTBd&P)$Ph-L*jNS9% zr#}A=@yY>lHGdxnBJt7Og!N^XXlw67K2P-9o|D^3O`>X(3iK}YBCWy7(JEbopMze4 zt>lOF!@pX%I*_QDWK3h+1FNG8I<`qRg}`xf2XSBqc2 zU#GtZr~yt9s$9g&2O!<0D$pK&0`qdHQ9E?0hOC85L)VOIe#@}SdiFf3 ztJKsC%Ro@yE5&VDueF-QRTtD+t&S@1@M})$edd8Bs02O^R@uMX&OX(i)pM$PGmCym zaP`q$4=mY#&cjrCc=yMtnTGGNIu9kTj%o9}l`$C)98tozXWHCYUmCk)GKu@OWP2ju z(`J)PbLPrG|CB8y_lsVW0U(gmW-SaZOQ*tpTaNjz6ACGIqA^GKmu=}=_46k4aZB%T z8Ex)e4N#1=!Ez;z+c;`=F~Y|ZtODD|@+-~RYSnWceHmMJwQ7#X2vJy*Q7+gKhvYM1 z>UmgOa;JuCxtaKgg#3dVc=A#{bnEygl({@4>V+06gLH5f8(2eK&da>cJ?1GrZQ3#y z)W!QeG+E7^b@0tW8+U9^@?=vQWc&a&E$ZW4+^5FdO+dlacZP}?VGDpEz7HM%x7cba8vXC;3cE*N`hFDOZofT#%UZlWzEbyA zRf?n;2|p6^%M}sEHR#9Lfb{HGCP;0 zXjk($a*3L8En86hq@Q0jA*$V(A$op4G6-m^2;Av|ZtnVDJOP~D0OX{yoznkRb7!9^ zs9Og;BLcYOBr5Uf8E!=ydVMyo5nYChP9lR?Cu+H5G_bSVcAFwFr#a-X6?FjwoX?`q z_aQ_EpHPk<;qb;J&(sL^@5@bc4M+BKqRN|dmO;;Gv<^9W=Z*Z)Lq|36Rs_^{`A%F0 z%0&24+m$r&qjg0SJIPJcpSV!L7;U|a6K5`z=Gjit*X_hy5Lel1VaPi3Jg{9me^`gH zC##Kgbf0;9cDH6mN4gBRA&*zN2vy8ce{A%ZjA+r>TI+T<#;CU%uPkWd3mi2l?-=ju zSOKH#eFg-06(o>&k)6DTajwPqkspe}geZR-=F{L?2VgucaHsx;qN|rdv)*hozHlJtSti8kg%-bAz0SvumxTU zlzn>jS8{tUCT`Ph^e$~MR(K2`s11#;%Q62KLGu8*x9Ps;w9bC*!GiwzUyi2`+^R!A>#yR>W>eIBf{4{j$ zuO6-mbk)gjtH1RPuqHZhVykeG5Xa{oB#9Y8pH3|=LyuZvugj=nzl)T4F}+M~4&5NA zMNTQRe8$%wf%K`#$@5Oho@w4Ic>=u7uiNV9&vSMK&)_sR%_Eqb=g}YJt}-`a_JB*C zx5(h-^ox}hD literal 0 HcmV?d00001 diff --git a/Test/Resources/assemblies/hello.x86.exe b/Test/Resources/assemblies/hello.x86.exe new file mode 100644 index 0000000000000000000000000000000000000000..1e0c064f6f2b319995056f48890cf4036bdb9caf GIT binary patch literal 3584 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 J?|*p$e*p+}20;J- literal 0 HcmV?d00001 diff --git a/Test/Resources/assemblies/libres.dll b/Test/Resources/assemblies/libres.dll new file mode 100644 index 0000000000000000000000000000000000000000..66a2b194d2fe39848e377e9128c3ce98549b0384 GIT binary patch literal 3072 zcmeHJO=ule6#nMrrKD*aD%R3~rV~=7_%l4yCoL*EOHl@jLg<`-zs?O+le2x#yn0d+vA6 z+25+2(&Z4Q@1 zn9V6?LMUncGGl{-cA*})?*jYve`n5A6N0_WJ14RWe3Y%rTxMDV_Ujf zE>(*z>lYGiIrJj6fy-QLiIH^H1_rfscWfwkloj`a7Vmq9ihBJ6C}Mzp6m7TW4))+dI2;cnzroNQbeS4ax5>gIT9)0e z;kmYag_2Y+_RqA{$k)t$cz!0TuLkM`1b#JEiBk^(OjGpYbu^M1KZjpMc|A#019R0k zR4s*5OQSfmISZ>{>Nk`#9yOYNpyINMFZwl=z!<#LkHQ5NcxzfpPNw`u)zwrXTPR_4 zRsFzE*E?Q=2C7k2^}4D*?WDX4Ep1e5fgir9>RM!3J+`jxtHCRWXPy|E`+nEw7q)JF z`ZM~zx%ArNVDb6~46yRHW%c!0*{vIrk5I`SJQI7(*(jV?tEr~It*pe+TZwhxr{BK) z{l@#h{P^}4zi!?b->k&et2c|;U69RYMYcuyC$;X3@thxz;!+UIcz$S_s+4ZDc()&g z?V7Ov1-JBRI%HnaF2v@17j9#hAbC5^xK16?#2d6Z$=*jEkrl z`ZE79uZ%@ZDWiPamv574L&p@*`YWPJ8F-S2taf~fyC1TT4X*@aLt+ouFAojspzISxtoL+Kr!KE0a8zTOrhQqj7-zLjtZP)u zSRpRx*gZSM$({5V{7!wj7IPE?6oO8c9 z_d921?(FE>A0q)E$?@O;aGSG~tkREGOI&W-_e~qVZob=nTa4W8o}9G;z2R3mCi|vc+*n+<%}f`#-${Xy#lnW|Hd4<5d>G6w00eX5Y>{2~3D($CpmiL(@@ z5T}n~TeEcj>^*`VQ4Oth30LhPF+9T|XW}8TvQBBsIjXrOo||wCFY&evDLtjMqx2=E zf5DGj{X^-5kaj^F6iu*{{zyf>Pv;n0CmU(n>Fd zruMUFp?-&2N&@e9&TuWtmB1Zw9?vowt=$n8BeiIq8DRy`K@ioS+rYJpqObPeBauoLLu_DO{l*e#$7bW;-sY4_09&`V50#glkm z9ERNC81-=!s7;(wk+-NXz@om0T`H2nbGVEQdT@n2YTPGa4LR1F!*)KWJ8^=@QKHUb zA4>RvE!>RjWDC)X8=R9%%=sD)7 z8P0kY*f?i!~FYbvv}mMiAyr+pHR)iLufJvmC-8yG%Ls zd=%VyZ_Y$vFj#cU6K23GpzI;Two68N4mq=GxiM_mt;E*2;eta>UX;^`7?nM5&N4AC zNyLmY6LmMV95YjJL(}(aMbn?R%4UGEdN>&J%_`MNZ8WNKFldCPT*q*Ys##Ihlvfz} z5lsu{QATCsCPSW6vux8}-6aYbq2;*~rfn=JYt1e(I|<`b$+E3*vB4p3K6nDu%i)Nz z=&dCk`EOco1$o;pI5p2-Q_^|QQ#Xx|o38Ha0y;0;`}D<;tK!se?^$zqk-l~5?DVdI z``5Ilu9U8cuFfXv&ONCXJ-M}m^VaQ*3$e8$2_e#(knHN}N_R1xkl~K*RNpwZL2T0Y zG`Ah%K72l!T+iWus;^ng39T=cBrvVehqax3iM?Ai8EH%NWmly3$~S#d+i}`AY9~E+ zc%f|8WV0q`eeYr*mg93+VtNNxzR&vnsGb$Mel{4Z9pGu z33Uc^g2%-=k=*%Rct~8r-c)^pUun4nd_7*5hJP`^f7%D2hi z|5`a2RUlTc#`DVAy>=~6M=+}apLr~POZaNR<%8-e*nXZFz$8}59uRbKxlEU<}?&xoT?=yRVLp+znDn8HM1HK|MPi@^kIvIJD^8D6Yn2=(i=U^|9|Yj-#LAf_y7O^ literal 0 HcmV?d00001 diff --git a/Test/Resources/assemblies/mma.exe b/Test/Resources/assemblies/mma.exe new file mode 100644 index 0000000000000000000000000000000000000000..78632f8dd47b46bcc7963e693e1a81675b63dc2e GIT binary patch literal 3584 zcmeHJU2GIp6h5=vnzlfLNDyMg%Px{iV7i4W4cXG|LJP%~R<v{ppbLN*^X1Q$FXpT8vf$PhbwXKgrj|~tFYfW@^BE6@Y?FzMPOSF~{6gEje zC$TU*89Z`f*kYjzIE7#CG=~RzNllb#CR(ok>w6@IE_4cUbCS;xeJ-1@kd6>7U8uVm znGr?Mm3Ir|T7l5$0iO-9Uzg2?O%)K~hNOrQ9npQ^n~)T?446Bj2V0dgK(G7U_TZ?n z9)U&1S^yk=S!n0cSEyf-#1^Aw3K-FPVA3Gtk=gze<*5Uw+d9z7HtIn8BX;B3SO=oI-7~x5T=Kzx2Td!zKrbo3&^xSgIlT&9Dm(Ttx)j(f60! zz;d|0({qZJ&HWtr%a+LnMFy!i0xNIXR#52=@HX?MfRkA_||>y-mB-I{<`bL!x#L=f4%bh z$_<+yVf!wh*}L>mdHA(+ubxR>`u-fzr%44xEk8(})#XO6dVlM>!#h2HV3w<%sF%dK zUa;kz!i2w{SVnP+FEMqO7^diIIP`?mw81s}M34QAer6H9JUrJBA!Nh*aRS2W3{iKi z?r=Fv^iyb7%I;V<_DRg>!&nDsKe!U{C6R{AXCLD&dbB#o5E+P?mG!zAKrB=DNKd>Q}vhC1j^S1b{qXN z$bn2)9q>B%StWNUEW_ZZmFG@WS)__WGmY6JXR5@}qi~EydReiITkW2d7LVVp&W+)m zM+GXO&H$aCUqv0itfiW(A9V_NI_R1WMC@PB;V51E=#zBctYfn>_XX}^Z=y?2B^Y;2 zuYm87-o(WC;O3qL6M^9t4BK;gZ=%9QqHo8twzMGxck*_HA%H7-6D8l>F3cJ37-F+y znZ75ysbI6|Iol24=;f{ia}3v-;v$%A%!W{m)q)KbI3{FJnTH5pd_d(I4$_ZQ`in)| zGS%SHjbbs;8Ab^Fk_d*}DeornY)Pnd$St^8!kDW>GBiGavILyGFy>oj%;{+^ZZhiD zYE%ZQ$HAyEOLE!`^D?)YE!WgRFn$Rxd@sn^v-$M l)19>@z#-jPeM1oB+rCY=+yNH;2K!~}El0S0@PFKazW@a#-Dv;- literal 0 HcmV?d00001 diff --git a/Test/Resources/assemblies/moda.netmodule b/Test/Resources/assemblies/moda.netmodule new file mode 100644 index 0000000000000000000000000000000000000000..8cc49983e620a143a87e240bfaf12c0e484e2d3b GIT binary patch literal 2048 zcmeHH%}*0i5dUo}-_nR00tfN6pfQ-N6+iHRq%B~>uC-XLc9L0W@9>lYR4>k2mvXX5a42t>=gXI6!N2 z6Idr?$^`t+>=C&W$KNOLwrwN1ZcJ|^=a+3yRJAJWVnvjSuB&`uNug`5uw5}eTM!ks zB+bsw_JJt%+ypRf#PDEYWOD1YIugkaqctol7Fxfj2nDSSEoOp%d|Wrv7GjYUvNOez zX#x%fPXi-0+=8bmpb*KsLIyavtK%<50Z<3q)JpnxgJd;*x#|=C;9AKSG!WHIT0jC= zG_`b8DXJkuX5Q0GYX@b3+z$1h#E+?PJJ%LN6RHB}p)-ts%F@_;ByFIBREqC{CSGkn zjpo6=*eOcdK8Rf5YR-tV^ITVk%(QtSJv=nbIhx=Q=R4T{5E!8F*DM!&ZM$WUM0_F} z$Mr81@P%Z0yXem^OpO!PNx#H;&QTU26StB-8VldWFXJ4#!`}GLlW%)bXiya+6&h98 zjEgu!<1Qml{4sH+a1VE3(D}VMMs>41C)oQEmxK6npgrlyB0;_`Ft!EUq6r(i*MnlF*{JXx`vhQ-UPNvS2* z*J7av%@UINuRlkfS2G{dQ?ah(w-;!AcmMW{-t+ZmG~q;C!06-A%*VQK>SFbpawk?x zvg+H)onO}Ko@c~cj0EL*lM2!W>@&-vq3@Ko?rXz#XH4mF$C)YGZa5Pu%_WEL5&h9l ZKx6`GpY1UL5q?kgp*{Tj=Kp#EzX6R`o`L`X literal 0 HcmV?d00001 diff --git a/Test/Resources/assemblies/modb.netmodule b/Test/Resources/assemblies/modb.netmodule new file mode 100644 index 0000000000000000000000000000000000000000..38522b293594af6daa2c4c0412a9e316d60a7097 GIT binary patch literal 2048 zcmeHHOHUI~6#k~A2t}HrgvbKC1vLbd5dpsBtHW8xns4KS6iKg?P@)09_Cg-QsD_d(N5foI5jAWbZ1*tbS z#?OVVXNG|ZErJ(w>9M`L?I4kA(CPwEkszArBrS+D#4H3U$}w)HJ&k#C!kQ>DF(B#x z4|M2q5z%G`kPpnmWd=BTc;@J+0BC}Jsw01YK#J;~T=Pgb^YSU@4-n!e&nE%Q>yETk zF~pFeFke$kTtyimTjlC&_H!m--Iq|6pvp-ZFhU5 ziw2E%Bby)3YGHTY>q@WQqhIM6=pEpj#bA;AO5FJf=%*%M*v@;7X)n5D;wQy;ubp#r zYSf-i7oDSXH*=(uYyYbk>?6NR+V=12|K;Fs2imS8r1UMS}?9|6x>%>*_?S&OT< zL@Qs$ILW6ZWB7nKbbV04l7C6GqK$HF&j`-G#C5;RqVGL9lS6`XO<4Hp6fNKdMTiY0G=-X24@rAL~4WD6SzQhF98x2PP;G>~6+Jz2uEu`G)o zMhhFtegM7bDJM+nw<@-0mZUzUN@dfMPF^}IW>LBb6C5vireRv9w?636_Kk`sG3dIo zWLO6gcT|l@M>4EJ6|4}_AV!oTjE+A>RQPIjYis0f)2pdZ>GZ=NeQn=R_kQEv?biOC zXLJe)x=3s11P-$t!1_Y=QH;+mz%*Z7UZKQ@y6BinA8Y@o2LrBfozPJP9nP?tW zv#GoQ!4m#K7ySWUu&62(b%T(AAbtW%7D(N&0*UaQJ2SCOtI|yci=6Sf=W)M#9{0{2 zdG&)YF#(`V-rECiQwlj|eDpBj^s$%k9K+X7?@rye8oN^)SG-tlM`15=`>NvxL71qv zR#6%#FHrThmgrhtIQz~&2K1kGlO7u8hBT92e^^1%cnB21w1q6cuYe9>|mb`(Y~;6 z0d}IVCA2@4oSZWa{3AczTXqyj9Zs9toE(?$2`xhotG6TVhXk5hx9FBwhsh)4081mL zQMaZukJMJeB-9j3u>k%IH5Kr4u0M|Wk)WTxzyFP_|BCFlcH%_$?R6c8Y1Gm2zP7I2 zu8u0IA9upY_u3V;siW8ngTC;@!OW!=ey8Nyh?%!8 zt<))nSdKMGX-Q3goS4J&S$Sd>EC*SXoOxxmP#zF8M$hGzppR$znbokH`uYt7VcQSe zcGvfF6%kK^oSloHCzM(9;;Vmt=iIq)@y6#rEdBb$-G#=qaho9!T@CF~t$3G4eZb}A zFsl3hDmN46thF{p2x{*Hlrs)Lu>Qjxu+01ULiQCMsUy1q)ra^6B;Str9H3qjE2Da; zMr9K%T;_Nl>(o}ThKsaUIKD|;=x+J`U&T9Z9QklImu1S4u*NHQ$6{0$5#xC9p&2v4 zM+nXQtofL3aMq1BnBI>cAxv@qE8$2hpfUkqs=dm z&qwGLQ&WSOo>{R>#5Q(JRXto`G?;7anD}eCUpklgMK5AKI#12?)8zV)*;DqN@Fd2& u8ulZ7Nl&r|=h$~lWZ%@k!)pF*o%D4;Pk0AZ_Mc(!+7r%m5dMF;1AhY+5$^#2 literal 0 HcmV?d00001 diff --git a/Test/Resources/assemblies/pinvoke.exe b/Test/Resources/assemblies/pinvoke.exe new file mode 100644 index 0000000000000000000000000000000000000000..2bd10bf8beb4f1198851ba58f3cd8ffa384d476d GIT binary patch literal 4096 zcmeHK&2JM&6o2bD5C@3p7YY@E!2t=OX7gD}Y8{2W5QktIOIrHYdH*en8 z?9SUve|($Th$xM*zE1Q2GegecSEE%dcO81zMc-$h9DZO;JvltLoqA9D5^w%R78s65Z%i3ji5bb~j6T^!hAc2v? zU?ec5YH@=y@$*cp7?3lxQLde6ulZ}vb+)EL_h9!5(>bE2T!gJ~ooM$~*>-rb5xUXt z0KbtSBz7W~6U=G$i8YgJJ#KIY1krU{$JzyFV#|TpR1Q3TxBms5bo^lI7?SEdPUFRo#w}y17FTu9?zcbe zKRI}kO}3K{oQI>H&xr10{($LXqP=i2W{qEv10R3Syel0)A-lI;|O< znr1Dpz3c*+G_qW!Z^Xcc73NML>Nc7cy!8&{shf6E(QsdO7w7;u_B{ifqIp9*hF$<} zGZjjcrnjg-g7yO+pu@mNDPw4xb|F%m-k~9S+d5?B@Fop#4puvzfW`DG%(TE$aGY}k zEPB5|5{*o&a>bWtDDuLpx*=`3ENN0H3Sw7j-z!mZB~D~OGo??Yo6xwF5fv{?DjhgU zUVBwZ(~cLC?Iuc7`R1gSpJK{aw3B!$q@|l-naW0QAxLnJDq?wDH)~(2gozhO`Q{~9rUwiLT#}Buz&hH;y z`>LH%sZ3@kr8C``Oom@6Y_Zb9vN{-bby)Sg?I1rrbE$n-v=d!a;l#2lO?fDNQ=8wSJUDu2uaF_Zn9qW$svkF4~PM zoT_!xP4%eVbF=>+ligXQl zf-Zq7;J&;Fz5qOF?oOgd>1QwaCfy2W>jJ*>x31=mY@Qt4u#@EBww16M(gG>7>j?3# zIjlO6##nbKft~_agZt@wFlr&D1X>>Ci!ZUXYIORk@f)TRX!JYW#MXv>9^PYejh(2) zkAQAJE{mq_Jajd*o3Zqx3p59x-EQb}Hi^*<5xb9iITU~=icGXs{nE#3i3{HzO7j`^Woe$ zC$7O5@{XYypo%^s6aTpnTj|-4k4Mff2fnCE9i!)rW(Vy4tdOCr%J|+G&0e0H>^+qg zapHt!$5){o&92Bed-lwp&Jib$Wl-{01Pp}nXttum)3LiG11IhcJXfn&EhN3J3Qjw5 zU{?pSB5*=)LB`4aW^XVh#D=j#S)$t|D=iV>0|`-uP5}4QD`QdQd#-7Awi89!zM6$Z zSK_1)E~stBGnh5|;5(LXMZ;&EhXftEf;eS)7Ht_lcTvXMv^vzVDgaG8Xfq!|SeJ_co5qe)s>?3^}MS#LcU*m+p@M*t+ SZC60l|7YN9_6@vt75Ez!HQdJl literal 0 HcmV?d00001 diff --git a/Test/Resources/assemblies/switch.exe b/Test/Resources/assemblies/switch.exe new file mode 100644 index 0000000000000000000000000000000000000000..114083242cc32328f47be8daa13ae6f111ee0280 GIT binary patch literal 3584 zcmeHJO>9(E6h3cS#-SBbKuTHAUZ!ZU*w+DS__3waKcL#u3DcHfjPT~oZTs~7jPJe~ zW?Yyq)WnU!#KbKzy3&OvCK8D;apQ`;OP0iiY>f-?JNLcmv=y-~HJtXId(XM&=R4=U zd*95xdXw6Ss2$_sL!#T5nev)Ho~>bfci(rr>6@K*58pOs?;c)Qb(E-t!AfX(!nS-r zh(t+>u<8rP7gO^^;RR)B?%LIHBne%ZCYm+csQ;&ihmkTeOR>t?7z8fveNp+PxUhVDuz& zy4T!$Y;U@+%j`_|2{U~x-92z%pl6_OV4yd36piT^po!wk6NW|;ms2}o=FAs!r%s$g z5a4ye?_>18gI*%(m%J`Uq2sS8EOj6FIrJ|UDTBK3Hcqdjy6ojVBL1!T-k>ZC*9`;g}#wXe|@`V=yIH_3qYI*rT) z<*F;sk-FhT_NpoCk_z#uB~RHw=sG1THdG`%nlHT}?TF?q$0yT{f{?5bt&Mlh%T+&e zJZVk_Ud3@`Sd?MSv8AF|VMR{hUzV;_*DEz1;mMS$k)*_t&9GH+TqkO@c4J%`Z=2B5 zt>3w{O3;ba43I2k2qu&~BI+?ZPlJZBH4QjFFtZUT*e6 zs{2Z4RW1eoblsK}hP1F61~(Kxhoi~+&q>blTJY+x)I29d*CvB-x-NA?bhD&1%Pzl% zxIv#Kk=LvLCQISX(k)oyGkQ9{O*fPhzq^IM(XT#2&(3QbBE-x1B;15>D^E0)Y8l+0 zAo?ZV*2<~WFy~%UfD>x0+fO08B3s9)Y|0~Go5LI3vR#6029PWbF;Ahtfd#)zZwmz`C=$Azv zWP>^8#&oiv+ zDZoF#Em;MQ2v1^jRjqosHm-?#Fb?brmL9t30-5+nKe*C^J3ow!)je0#WT@Dd6`tig%Th&48?zyl5bMEa$`W^H)YyawA2*=#Ef4AE z8sn9U>)870G_6V{I}}HV!m5g9{N-Sqcur)sA95>cS3~4XWN1S9Ruwp9xez)v+~6xx zZ8Pf0W>f)c#lh8RSNV>el{M)Km-%ScQZs%ncvFU1QFX>`d?C=rWy@7EDM|+!dIXv# o^r21IM~2p$0E3aC<`aUzPx}dNy8|NrT~#=_ZI360|Dz843H|$}82|tP literal 0 HcmV?d00001 diff --git a/Test/Resources/assemblies/text_file.txt b/Test/Resources/assemblies/text_file.txt new file mode 100644 index 000000000..5de1caf88 --- /dev/null +++ b/Test/Resources/assemblies/text_file.txt @@ -0,0 +1 @@ +Cecil ftw! diff --git a/Test/Resources/assemblies/varargs.exe b/Test/Resources/assemblies/varargs.exe new file mode 100644 index 0000000000000000000000000000000000000000..4e3acf4cda6b588ed03f99dc4657124bbbc34e01 GIT binary patch literal 2048 zcmeHH&rcIk5dL22mQtj#qFjveQP4ERYzV{<5@Jf_w}6B~G+tzBUrOV4m%MHX5+%ly zM-Rroz!-0O;6RKA{{f6wFQx~s{sSJwneHwi0gP9}WZ%qu-^{+5H~ZR|2QSeCAWCa* z57;Kll5ObI)iVkwuYOEot7WHiTTJhCF07QRa#gz}ZB=B!avax_%S!5+Bg>8)xto_2 zx2VjvwnTTZ_1q{hEh4z{V|OI1R!35_in!lY#Am;!$x2#TTC5})igDj8p~Vsb;#ufi zM4xXw2R49y3SOjveBd8zvcS1x1AieUKquIjIN^zX1el&$_XzKDuM}$>An2P=LnN?d zYGu2Hpoc8coD-vUNU}ig5d0_ibJ|bm-XbvYP6BlS(8KdPQpwLfO}F>Pk)Q;6KXn1W zkRd10102u4mAseaVi`JELX)>D`G}H=L-JS6keBGm<)?B2oaoPDtVwV217&>vr%93gIt@C}aTYMOrEUBHA&F%jo6}j>zB<3=D_N(2QHG+3FVZkE@=lU|5$XJ*6$r)tIk2Ub&)( zs#TQZO;}FRRxk@3TeGyKX?~Sz!PRzo8Dp-CoTX7Ey#ch9U||C;96X|0_v+uCKAHM7 z{(kKFrJ>sO*D$0Isg@=KB5DYcq?w7B5fQ`jc-)AJB-?1SNE!6*hjiF1@P&POfDe1& xeLdhF-gfoqx|*@dj^C(KX3^&RK>ujhAhQkcOr0HnVUeJ8}v=>K{GzX5YSeQ5vy literal 0 HcmV?d00001 diff --git a/Test/Resources/cs/CustomAttributes.cs b/Test/Resources/cs/CustomAttributes.cs new file mode 100644 index 000000000..4c52c7c51 --- /dev/null +++ b/Test/Resources/cs/CustomAttributes.cs @@ -0,0 +1,152 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; + +[assembly: Foo ("bingo")] + +[assembly: TypeForwardedTo (typeof (System.Diagnostics.DebuggableAttribute))] + +enum Bingo : short { + Fuel = 2, + Binga = 4, +} + +/* +in System.Security.AccessControl + + [Flags] + public enum AceFlags : byte { + None = 0, + ObjectInherit = 0x01, + ContainerInherit = 0x02, + NoPropagateInherit = 0x04, + InheritOnly = 0x08, + InheritanceFlags = ObjectInherit | ContainerInherit | NoPropagateInherit | InheritOnly, + Inherited = 0x10, + SuccessfulAccess = 0x40, + FailedAccess = 0x80, + AuditFlags = SuccessfulAccess | FailedAccess, + } +*/ + +class FooAttribute : Attribute { + + internal class Token { + } + + public FooAttribute () + { + } + + public FooAttribute (string str) + { + } + + public FooAttribute (sbyte a, byte b, bool c, bool d, ushort e, short f, char g) + { + } + + public FooAttribute (int a, uint b, float c, long d, ulong e, double f) + { + } + + public FooAttribute (char [] chars) + { + } + + public FooAttribute (object a, object b) + { + } + + public FooAttribute (Bingo bingo) + { + } + + public FooAttribute (System.Security.AccessControl.AceFlags flags) + { + } + + public FooAttribute (Type type) + { + } + + public int Bang { get { return 0; } set {} } + public string Fiou { get { return "fiou"; } set {} } + + public object Pan; + public string [] PanPan; + + public Type Chose; +} + +[Foo ("bar")] +class Hamster { +} + +[Foo ((string) null)] +class Dentist { +} + +[Foo (-12, 242, true, false, 4242, -1983, 'c')] +class Steven { +} + +[Foo (-100000, 200000, 12.12f, long.MaxValue, ulong.MaxValue, 64.646464)] +class Seagull { +} + +[Foo (new char [] { 'c', 'e', 'c', 'i', 'l' })] +class Rifle { +} + +[Foo ("2", 2)] +class Worm { +} + +[Foo (new object [] { "2", 2, 'c' }, new object [] { new object [] { 1, 2, 3}, null })] +class Sheep { +} + +[Foo (Bang = 42, PanPan = new string [] { "yo", "yo" }, Pan = new object [] { 1, "2", '3' }, Fiou = null)] +class Angola { +} + +[Foo (Pan = "fiouuu")] +class BoxedStringField { +} + +[Foo (Bingo.Fuel)] +class Zero { +} + +[Foo (System.Security.AccessControl.AceFlags.NoPropagateInherit)] +class Ace { +} + +[Foo (new object [] { Bingo.Fuel, Bingo.Binga }, null, Pan = System.Security.AccessControl.AceFlags.NoPropagateInherit)] +class Bzzz { +} + +[Foo (typeof (Bingo))] +class Typed { +} + +[Foo (typeof (FooAttribute.Token))] +class NestedTyped { +} + +[Foo (Chose = typeof (Typed))] +class Truc { +} + +[Foo (Chose = (Type) null)] +class Machin { +} + +[Foo (typeof (Dictionary<,>))] +class OpenGeneric { +} + +[Foo (typeof (Dictionary[,]>))] +class ClosedGeneric { +} diff --git a/Test/Resources/cs/Events.cs b/Test/Resources/cs/Events.cs new file mode 100644 index 000000000..22311060f --- /dev/null +++ b/Test/Resources/cs/Events.cs @@ -0,0 +1,8 @@ +using System; + +delegate void Pan (object sender, EventArgs args); + +abstract class Foo { + + public abstract event Pan Bar; +} diff --git a/Test/Resources/cs/Fields.cs b/Test/Resources/cs/Fields.cs new file mode 100644 index 000000000..b85a57d1c --- /dev/null +++ b/Test/Resources/cs/Fields.cs @@ -0,0 +1,41 @@ +using System; +using System.Runtime.InteropServices; + +class Foo { + Bar bar; +} + +class Bar { + volatile int oiseau; +} + +class Baz { + bool @bool; + char @char; + sbyte @sbyte; + byte @byte; + short int16; + ushort uint16; + int int32; + uint uint32; + long int64; + ulong uint64; + float single; + double @double; + string @string; + object @object; +} + +enum Pim { + Pam = 1, + Poum = 2, +} + +class PanPan { + + public const PanPan Peter = null; + public const string QQ = "qq"; + public const string nil = null; + public const object obj = null; + public const int [] ints = null; +} diff --git a/Test/Resources/cs/Generics.cs b/Test/Resources/cs/Generics.cs new file mode 100644 index 000000000..5c7d5adda --- /dev/null +++ b/Test/Resources/cs/Generics.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; + +class Foo {} + +abstract class Bar { + + T bang; + + public abstract Bar Self (); + + public abstract Bar SelfString (); +} + +abstract class Baz { + + public abstract TBang Gazonk (object o); + + public abstract Bar Gazoo (); +} + +class Zap {} +interface IZoom {} + +class Bongo where T : Zap, IZoom { + + enum Dang { + Ding = 2, + Dong = 12, + } +} + +class Parent {} +class Child : Parent { + public T [] array; +} +class TamChild : Child {} +class RecChild : Child {} + +class Tamtam { + + static void Foo (TFoo tf) + { + } + + static void Bar () + { + Foo (2); + } + + static List Beta () + { + return new List (); + } + + static List Charlie () + { + return new List (); + } +} + +class It { + + public IEnumerable> Pwow () + { + yield return new Foo (); + yield return new Foo (); + yield return new Foo (); + } + + public void ReadPwow () + { + foreach (Foo foo in Pwow ()) + Tac (foo); + } + + public void Tac (T t) + { + } +} + +class Duel where T2 : T1 where T3 : T2 {} + +class ChildReader { + + public int Read (TamChild t) + { + return t.array.Length; + } +} + +struct Nilible where T : struct { + public T t; +} + +class Null { + + public static int Compare (Nilible x, Nilible y) where T : struct + { + return Comparer.Default.Compare (x.t, y.t); + } +} + +public class DoubleFuncClass { + public void Test () { Test (); Test (); } + public void Test () { Test (); Test (); } + public void Test () { Test (); Test (); } +} + +public class DoubleFuncClass { + public void Test () { Test (); Test (); } + public void Test () { Test (); Test (); } + public void Test () { Test (); Test (); } +} diff --git a/Test/Resources/cs/Interfaces.cs b/Test/Resources/cs/Interfaces.cs new file mode 100644 index 000000000..486c268a4 --- /dev/null +++ b/Test/Resources/cs/Interfaces.cs @@ -0,0 +1,22 @@ +using System; + +interface IFoo {} +interface IBar : IFoo {} + +abstract class Bar : IBar {} + +interface IBingo { + void Foo (); + void Bar (); +} + +class Bingo : IBingo { + + void IBingo.Foo () + { + } + + void IBingo.Bar () + { + } +} diff --git a/Test/Resources/cs/Layouts.cs b/Test/Resources/cs/Layouts.cs new file mode 100644 index 000000000..3a332fd88 --- /dev/null +++ b/Test/Resources/cs/Layouts.cs @@ -0,0 +1,16 @@ +using System; +using System.Runtime.InteropServices; + +[StructLayout (LayoutKind.Explicit, Size = 16)] +public struct Foo { + [FieldOffset (0)] public ushort Bar; + [FieldOffset (2)] public ushort Baz; + [FieldOffset (4)] public uint Gazonk; +} + +class Babar { +} + +class Locke { + public int [] integers = new int [] { 1, 2, 3, 4 }; +} diff --git a/Test/Resources/cs/Methods.cs b/Test/Resources/cs/Methods.cs new file mode 100644 index 000000000..36c0383a6 --- /dev/null +++ b/Test/Resources/cs/Methods.cs @@ -0,0 +1,21 @@ +using System; +using System.Runtime.InteropServices; + +abstract class Foo { + public abstract void Bar (int a); +} + +class Bar { + + [DllImport ("foo.dll")] + public extern static void Pan ([MarshalAs (UnmanagedType.I4)] int i); +} + +public class Baz { + + public void PrintAnswer () + { + Console.WriteLine ("answer: {0}", 42); + } +} + diff --git a/Test/Resources/cs/NestedTypes.cs b/Test/Resources/cs/NestedTypes.cs new file mode 100644 index 000000000..2129e6b25 --- /dev/null +++ b/Test/Resources/cs/NestedTypes.cs @@ -0,0 +1,16 @@ +class Foo { + class Bar { + class Baz { + } + } +} + +class Bingo { + public class Fuel { + } + + public static Fuel GetFuel () + { + return null; + } +} diff --git a/Test/Resources/cs/Properties.cs b/Test/Resources/cs/Properties.cs new file mode 100644 index 000000000..961a81a92 --- /dev/null +++ b/Test/Resources/cs/Properties.cs @@ -0,0 +1,18 @@ +using System; + +abstract class Foo { + + public abstract int Bar { get; } + public abstract string Baz { get; set; } + public abstract string Gazonk { set; } +} + +abstract class Bar { + + public abstract Foo this [int a, string s] { set; } +} + +class Baz { + + public string Bingo { get; set; } +} diff --git a/Test/Resources/il/hello.il b/Test/Resources/il/hello.il new file mode 100644 index 000000000..a71b8fb4b --- /dev/null +++ b/Test/Resources/il/hello.il @@ -0,0 +1,84 @@ +.assembly extern mscorlib +{ + .publickeytoken = (B7 7A 5C 56 19 34 E0 89) + .ver 2:0:0:0 +} + +.assembly Hello {} + +.module Hello.dll + +.class private auto ansi Foo { + + .method public specialname rtspecialname instance void .ctor () cil managed + { + ldarg.0 + call instance void [mscorlib]System.Object::.ctor () + ret + } + + .method public static void Bar (int32 a, int32 b) + { + .locals init (int32 res) + ldarg.0 + ldarg.1 + mul + stloc.0 + ldloc.0 + call void Foo::Baz (int32) + ret + } + + .method public static void Baz (int32 a) + { + ret + } + + .method public void Gazonk () + { + ldarg 0 + pop + ret + } + + .method public static void PrintEmpty () + { + ldsfld string [mscorlib]System.String::Empty + call void [mscorlib]System.Console::WriteLine(string) + ret + } + + .method public static bool TestFilter (bool b) cil managed + { + .maxstack 2 + .locals init (bool flag) + beginTry: + newobj instance void [mscorlib]System.Exception::.ctor () + throw + leave endCatch + startFilter: + pop + ldarg.0 + endfilter + startCatch: + ldc.i4.1 + stloc.0 + leave return + leave endCatch + endCatch: + L_001b: ldc.i4.0 + L_001c: stloc.0 + return: + L_001d: ldloc.0 + L_001e: ret + .try beginTry to startFilter filter startFilter handler startCatch to endCatch + } + + .method public static !!T GetState(string var, [opt] !!T defaultValue) cil managed + { + .param [2] = nullref + + ldarg.1 + ret + } +} diff --git a/Test/Resources/il/methodspecs.il b/Test/Resources/il/methodspecs.il new file mode 100644 index 000000000..b8006f322 --- /dev/null +++ b/Test/Resources/il/methodspecs.il @@ -0,0 +1,43 @@ + +.assembly extern mscorlib +{ + .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) + .ver 2:0:0:0 +} + +.assembly MethodSpecs +{ +} + +.module MethodSpecs.dll + +.class private auto ansi beforefieldinit Tamtam + extends [mscorlib]System.Object +{ + .method private hidebysig static void Foo(!!TFoo tf) cil managed + { + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method Tamtam::Foo + + .method private hidebysig static void Bar() cil managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldc.i4.2 + IL_0001: call void Tamtam::Foo(!!0) + IL_0006: ret + } // end of method Tamtam::Bar + + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method Tamtam::.ctor + +} // end of class Tamtam diff --git a/Test/Resources/il/others.il b/Test/Resources/il/others.il new file mode 100644 index 000000000..60713af30 --- /dev/null +++ b/Test/Resources/il/others.il @@ -0,0 +1,81 @@ +.assembly extern mscorlib +{ + .publickeytoken = (B7 7A 5C 56 19 34 E0 89) + .ver 2:0:0:0 +} + +.assembly Others {} + +.module Others.dll + +.class private auto ansi Others { + + .field private string _context + + .method public specialname instance string get_Context () cil managed + { + ldarg.0 + ldfld string Others::_context + ret + } + + .method public specialname instance void set_Context (string val) cil managed + { + ldarg.0 + ldarg.1 + stfld string Others::_context + ret + } + + .method public specialname instance void let_Context (string val) cil managed + { + ldarg.0 + ldarg.1 + stfld string Others::_context + ret + } + + .method public specialname instance void bet_Context (string val) cil managed + { + ldarg.0 + ldarg.1 + stfld string Others::_context + ret + } + + .property instance string Context () { + .get instance string Others::get_Context () + .set instance void Others::set_Context (string val) + .other instance void Others::let_Context (string val) + .other instance void Others::bet_Context (string val) + } + + .field private class [mscorlib]System.EventHandler _handler + + .method public specialname instance void remove_Handler (class [mscorlib]System.EventHandler) cil managed + { + ret + } + + .method public specialname instance void add_Handler (class [mscorlib]System.EventHandler) cil managed + { + ret + } + + .method public specialname instance void dang_Handler (class [mscorlib]System.EventHandler) cil managed + { + ret + } + + .method public specialname instance void fang_Handler (class [mscorlib]System.EventHandler) cil managed + { + ret + } + + .event [mscorlib]System.EventHandler Handler { + .removeon instance void Others::remove_Handler (class [mscorlib]System.EventHandler) + .addon instance void Others::add_Handler (class [mscorlib]System.EventHandler) + .other instance void Others::dang_Handler (class [mscorlib]System.EventHandler) + .other instance void Others::fang_Handler (class [mscorlib]System.EventHandler) + } +} diff --git a/Test/Resources/il/types.il b/Test/Resources/il/types.il new file mode 100644 index 000000000..4c9acafb5 --- /dev/null +++ b/Test/Resources/il/types.il @@ -0,0 +1,46 @@ +.assembly extern mscorlib +{ + .publickeytoken = (B7 7A 5C 56 19 34 E0 89) + .ver 2:0:0:0 +} + +.assembly Types {} + +.module Types.dll + +.class private auto ansi Types { + + .field public int32[,] rank_two + .field public int32[0...,0...] rank_two_low_bound_zero + .field public int32[-1...4] rank_one_low_bound_m1 + + .method public specialname rtspecialname instance void .ctor () cil managed + { + ldarg.0 + call instance void [mscorlib]System.Object::.ctor () + ret + } +} + +.class interface private abstract auto ansi IFoo +{ +} + +.class interface private abstract auto ansi IBar + implements IFoo +{ +} + +.class interface private abstract IBaz + implements IBar, IFoo +{ +} + +.class private Fields { + + .field private static literal int32 int32_int16 = int16(0x0001) + .field private static literal int16 int16_int32 = int32(0x00000001) + .field private static literal char char_int16 = int16(0x0001) + .field private static literal int16 int16_char = char(0x0073) + .field private static literal int32 int32_nullref = nullref +} diff --git a/Test/libs/nunit-2.4.8/license.txt b/Test/libs/nunit-2.4.8/license.txt new file mode 100644 index 000000000..fef69103d --- /dev/null +++ b/Test/libs/nunit-2.4.8/license.txt @@ -0,0 +1,15 @@ +Copyright © 2002-2007 Charlie Poole +Copyright © 2002-2004 James W. Newkirk, Michael C. Two, Alexei A. Vorontsov +Copyright © 2000-2002 Philip A. Craig + +This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment (see the following) in the product documentation is required. + +Portions Copyright © 2002-2007 Charlie Poole or Copyright © 2002-2004 James W. Newkirk, Michael C. Two, Alexei A. Vorontsov or Copyright © 2000-2002 Philip A. Craig + +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source distribution. diff --git a/Test/libs/nunit-2.4.8/nunit.core.dll b/Test/libs/nunit-2.4.8/nunit.core.dll new file mode 100755 index 0000000000000000000000000000000000000000..a31edfdd9e8d70f4455253951c5113a17b081595 GIT binary patch literal 90112 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 Di0l1l literal 0 HcmV?d00001 diff --git a/Test/libs/nunit-2.4.8/nunit.framework.dll b/Test/libs/nunit-2.4.8/nunit.framework.dll new file mode 100755 index 0000000000000000000000000000000000000000..2a0a0aa3266b37dbaaa6c418500da203a2fa67eb GIT binary patch literal 77824 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 literal 0 HcmV?d00001 diff --git a/dbg/Program.cs b/dbg/Program.cs new file mode 100644 index 000000000..260b7445f --- /dev/null +++ b/dbg/Program.cs @@ -0,0 +1,60 @@ +using System; +using System.IO; +using System.Diagnostics; +using System.Linq; + +using Mono.Cecil.Mdb; + +namespace Mono.Cecil.Debug { + + interface IFoo { } + interface IBar : IFoo { } + + abstract class Bar : IBar { } + + delegate void Action (); + + class Program { + + static int Answer () + { + return 42; + } + + static void Main (string [] args) + { + Time (() => { + var module = GetCurrentModule (); + + module.Write ("dbg.rt.exe"); + }); + } + + static void Time (Action action) + { + var watch = new Stopwatch (); + watch.Start (); + action (); + watch.Stop (); + + Console.WriteLine ("Elapsed: {0}", watch.Elapsed); + } + + //static TypeDefinition GetCurrentType () + //{ + // return GetCurrentModule ().Types [typeof (Program).FullName]; + //} + + static ModuleDefinition GetModule (string module) + { + return ModuleDefinition.ReadModule (module, new ReaderParameters { + ReadingMode = ReadingMode.Deferred, + }); + } + + static ModuleDefinition GetCurrentModule () + { + return GetModule (typeof (object).Module.FullyQualifiedName); + } + } +} diff --git a/dbg/Properties/AssemblyInfo.cs b/dbg/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..5789c5e55 --- /dev/null +++ b/dbg/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle ("dbg")] +[assembly: AssemblyDescription ("")] +[assembly: AssemblyConfiguration ("")] +[assembly: AssemblyCompany ("")] +[assembly: AssemblyProduct ("dbg")] +[assembly: AssemblyCopyright ("Copyright © 2008")] +[assembly: AssemblyTrademark ("")] +[assembly: AssemblyCulture ("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible (false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid ("6f6c7314-315c-47b7-928e-e9ad1330ff1a")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion ("1.0.0.0")] +[assembly: AssemblyFileVersion ("1.0.0.0")] diff --git a/dbg/dbg.csproj b/dbg/dbg.csproj new file mode 100644 index 000000000..5b79ac114 --- /dev/null +++ b/dbg/dbg.csproj @@ -0,0 +1,85 @@ + + + + net_4_0_Debug + AnyCPU + 9.0.30729 + 2.0 + {89A775F3-64AB-485E-B958-60C25254B732} + Exe + Properties + dbg + dbg + 512 + + + true + full + false + bin\net_3_5_Debug\ + DEBUG;TRACE;NET_3_5 + prompt + 4 + v3.5 + + + pdbonly + true + bin\net_3_5_Release\ + TRACE;NET_3_5 + prompt + 4 + v3.5 + + + true + full + false + bin\net_4_0_Debug\ + DEBUG;TRACE;NET_3_5;NET_4_0 + prompt + 4 + v4.0 + + + pdbonly + true + bin\net_4_0_Release\ + TRACE;NET_3_5;NET_4_0 + prompt + 4 + v4.0 + + + + + 3.5 + + + + + + + + + {D68133BD-1E63-496E-9EDE-4FBDBF77B486} + Mono.Cecil + + + {FBC6DD59-D09D-499C-B03C-99C1C78FF2AC} + Mono.Cecil.Rocks + + + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD} + Mono.Cecil.Mdb + + + + + \ No newline at end of file diff --git a/mono.snk b/mono.snk new file mode 100644 index 0000000000000000000000000000000000000000..380116c18fc37e37caee38d5c7f00553381fbf9e GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50097b6`6O^&^nH5>Uu78=+UptljwyRbd@W# zfT1jrG)GMY1|&zrehz5BfKzYJJU_lK`N?_CnS^!a2I$U$-CGYe4Z#kRzb@|2hf5@P z3{ZjF>U2l_+WIGZBHl;V|LR1Rbfo$G&xFxXX$X^mC{4Z7Uq;RU5~00#T8$V?4 zm0(Z@pa!7K?(Fv6`Sy%zIG6>&?npz0UV%?bgx!7tH#C%jM34vHZxVr2-GyqR){Wb_ z{XsWBT$ZExT8-J6M|x?bD~-_)p-JamyVJi9497FdEQ65@I<~MMyg{tluUqokqOaxj zlhqj9JtQiyyKdy8TBK}e2S{tm<$7FGKad_^`^?rYM0;cj^51yOyC%wV#(=?x_-cVmn-um!xGBCj903_NLpqj#fY94K!%&o7 zw|E3wgmzMa{N+PDQQ4BhoE7KBA!Hxyi2D5IJ4civ7g7A4#@Va i>Ut2fuAI+%0QCxKtaJZ4tp|R<30%KGIZqYwf2q$ + + + net_4_0_Debug + AnyCPU + 9.0.30729 + 2.0 + {FBC6DD59-D09D-499C-B03C-99C1C78FF2AC} + Library + Properties + Mono.Cecil.Rocks + Mono.Cecil.Rocks + 512 + true + ..\mono.snk + + + true + full + false + ..\bin\net_3_5_Debug\ + DEBUG;TRACE;INSIDE_ROCKS;NET_3_5 + prompt + 4 + v3.5 + + + pdbonly + true + ..\bin\net_3_5_Release\ + TRACE;INSIDE_ROCKS;NET_3_5 + prompt + 4 + v3.5 + + + true + full + false + ..\bin\net_4_0_Debug\ + DEBUG;TRACE;INSIDE_ROCKS;NET_3_5;NET_4_0 + prompt + 4 + v4.0 + + + pdbonly + true + ..\bin\net_4_0_Release\ + TRACE;INSIDE_ROCKS;NET_3_5;NET_4_0 + prompt + 4 + v4.0 + + + true + full + false + ..\bin\silverlight_Debug\ + DEBUG;TRACE;NET_3_5;NET_4_0;SILVERLIGHT + prompt + 4 + Silverlight + v4.0 + + + pdbonly + true + ..\bin\silverlight_Release\ + TRACE;NET_3_5;NET_4_0;SILVERLIGHT + prompt + 4 + Silverlight + v4.0 + + + true + full + false + ..\bin\winphone_Debug\ + DEBUG;TRACE;NET_3_5;NET_4_0;SILVERLIGHT;CF + prompt + 4 + WindowsPhone + Silverlight + v4.0 + + + pdbonly + true + ..\bin\winphone_Release\ + TRACE;NET_3_5;NET_4_0;SILVERLIGHT;CF + prompt + 4 + WindowsPhone + Silverlight + v4.0 + + + + 3.5 + + + + + + + + + + + + + + + + {D68133BD-1E63-496E-9EDE-4FBDBF77B486} + Mono.Cecil + + + + + \ No newline at end of file diff --git a/rocks/Mono.Cecil.Rocks/AssemblyInfo.cs b/rocks/Mono.Cecil.Rocks/AssemblyInfo.cs new file mode 100644 index 000000000..ae2b650eb --- /dev/null +++ b/rocks/Mono.Cecil.Rocks/AssemblyInfo.cs @@ -0,0 +1,41 @@ +// +// AssemblyInfo.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Reflection; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle ("Mono.Cecil.Rocks")] +[assembly: AssemblyProduct ("Mono.Cecil")] +[assembly: AssemblyCopyright ("Copyright © 2008 - 2010 Jb Evain")] + +[assembly: CLSCompliant (false)] +[assembly: ComVisible (false)] + +[assembly: AssemblyVersion ("0.9.4.0")] +[assembly: AssemblyFileVersion ("0.9.4.0")] diff --git a/rocks/Mono.Cecil.Rocks/Functional.cs b/rocks/Mono.Cecil.Rocks/Functional.cs new file mode 100644 index 000000000..a6f1a45ba --- /dev/null +++ b/rocks/Mono.Cecil.Rocks/Functional.cs @@ -0,0 +1,59 @@ +// +// Functional.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Generic; + +namespace Mono.Cecil.Rocks { + + static class Functional { + + public static System.Func Y (System.Func, System.Func> f) + { + System.Func g = null; + g = f (a => g (a)); + return g; + } + + public static IEnumerable Prepend (this IEnumerable source, TSource element) + { + if (source == null) + throw new ArgumentNullException ("source"); + + return PrependIterator (source, element); + } + + static IEnumerable PrependIterator (IEnumerable source, TSource element) + { + yield return element; + + foreach (var item in source) + yield return item; + } + } +} diff --git a/rocks/Mono.Cecil.Rocks/ILParser.cs b/rocks/Mono.Cecil.Rocks/ILParser.cs new file mode 100644 index 000000000..3fb014e32 --- /dev/null +++ b/rocks/Mono.Cecil.Rocks/ILParser.cs @@ -0,0 +1,236 @@ +// +// ILParser.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +using Mono.Cecil.Cil; +using Mono.Collections.Generic; + +namespace Mono.Cecil.Rocks { + +#if INSIDE_ROCKS + public +#endif + interface IILVisitor { + void OnInlineNone (OpCode opcode); + void OnInlineSByte (OpCode opcode, sbyte value); + void OnInlineByte (OpCode opcode, byte value); + void OnInlineInt32 (OpCode opcode, int value); + void OnInlineInt64 (OpCode opcode, long value); + void OnInlineSingle (OpCode opcode, float value); + void OnInlineDouble (OpCode opcode, double value); + void OnInlineString (OpCode opcode, string value); + void OnInlineBranch (OpCode opcode, int offset); + void OnInlineSwitch (OpCode opcode, int [] offsets); + void OnInlineVariable (OpCode opcode, VariableDefinition variable); + void OnInlineArgument (OpCode opcode, ParameterDefinition parameter); + void OnInlineSignature (OpCode opcode, CallSite callSite); + void OnInlineType (OpCode opcode, TypeReference type); + void OnInlineField (OpCode opcode, FieldReference field); + void OnInlineMethod (OpCode opcode, MethodReference method); + } + +#if INSIDE_ROCKS + public +#endif + static class ILParser { + + class ParseContext { + public CodeReader Code { get; set; } + public MetadataReader Metadata { get; set; } + public Collection Variables { get; set; } + public IILVisitor Visitor { get; set; } + } + + public static void Parse (MethodDefinition method, IILVisitor visitor) + { + if (method == null) + throw new ArgumentNullException ("method"); + if (visitor == null) + throw new ArgumentNullException ("visitor"); + if (!method.HasBody || !method.HasImage) + throw new ArgumentException (); + + var context = CreateContext (method, visitor); + var code = context.Code; + + code.MoveTo (method.RVA); + + var flags = code.ReadByte (); + + switch (flags & 0x3) { + case 0x2: // tiny + int code_size = flags >> 2; + ParseCode (code_size, context); + break; + case 0x3: // fat + code.position--; + ParseFatMethod (context); + break; + default: + throw new NotSupportedException (); + } + } + + static ParseContext CreateContext (MethodDefinition method, IILVisitor visitor) + { + var code = method.Module.Read (method, (_, reader) => CodeReader.CreateCodeReader (reader)); + + return new ParseContext { + Code = code, + Metadata = code.reader, + Visitor = visitor, + }; + } + + static void ParseFatMethod (ParseContext context) + { + var code = context.Code; + + code.Advance (4); + var code_size = code.ReadInt32 (); + var local_var_token = code.ReadToken (); + + if (local_var_token != MetadataToken.Zero) + context.Variables = code.ReadVariables (local_var_token); + + ParseCode (code_size, context); + } + + static void ParseCode (int code_size, ParseContext context) + { + var code = context.Code; + var metadata = context.Metadata; + var visitor = context.Visitor; + + var start = code.position; + var end = start + code_size; + + while (code.position < end) { + var il_opcode = code.ReadByte (); + var opcode = il_opcode != 0xfe + ? OpCodes.OneByteOpCode [il_opcode] + : OpCodes.TwoBytesOpCode [code.ReadByte ()]; + + switch (opcode.OperandType) { + case OperandType.InlineNone: + visitor.OnInlineNone (opcode); + break; + case OperandType.InlineSwitch: + var length = code.ReadInt32 (); + var branches = new int [length]; + for (int i = 0; i < length; i++) + branches [i] = code.ReadInt32 (); + visitor.OnInlineSwitch (opcode, branches); + break; + case OperandType.ShortInlineBrTarget: + visitor.OnInlineBranch (opcode, code.ReadSByte ()); + break; + case OperandType.InlineBrTarget: + visitor.OnInlineBranch (opcode, code.ReadInt32 ()); + break; + case OperandType.ShortInlineI: + if (opcode == OpCodes.Ldc_I4_S) + visitor.OnInlineSByte (opcode, code.ReadSByte ()); + else + visitor.OnInlineByte (opcode, code.ReadByte ()); + break; + case OperandType.InlineI: + visitor.OnInlineInt32 (opcode, code.ReadInt32 ()); + break; + case OperandType.InlineI8: + visitor.OnInlineInt64 (opcode, code.ReadInt64 ()); + break; + case OperandType.ShortInlineR: + visitor.OnInlineSingle (opcode, code.ReadSingle ()); + break; + case OperandType.InlineR: + visitor.OnInlineDouble (opcode, code.ReadDouble ()); + break; + case OperandType.InlineSig: + visitor.OnInlineSignature (opcode, code.GetCallSite (code.ReadToken ())); + break; + case OperandType.InlineString: + visitor.OnInlineString (opcode, code.GetString (code.ReadToken ())); + break; + case OperandType.ShortInlineArg: + visitor.OnInlineArgument (opcode, code.GetParameter (code.ReadByte ())); + break; + case OperandType.InlineArg: + visitor.OnInlineArgument (opcode, code.GetParameter (code.ReadInt16 ())); + break; + case OperandType.ShortInlineVar: + visitor.OnInlineVariable (opcode, GetVariable (context, code.ReadByte ())); + break; + case OperandType.InlineVar: + visitor.OnInlineVariable (opcode, GetVariable (context, code.ReadInt16 ())); + break; + case OperandType.InlineTok: + case OperandType.InlineField: + case OperandType.InlineMethod: + case OperandType.InlineType: + var member = metadata.LookupToken (code.ReadToken ()); + switch (member.MetadataToken.TokenType) { + case TokenType.TypeDef: + case TokenType.TypeRef: + case TokenType.TypeSpec: + visitor.OnInlineType (opcode, (TypeReference) member); + break; + case TokenType.Method: + case TokenType.MethodSpec: + visitor.OnInlineMethod (opcode, (MethodReference) member); + break; + case TokenType.Field: + visitor.OnInlineField (opcode, (FieldReference) member); + break; + case TokenType.MemberRef: + var field_ref = member as FieldReference; + if (field_ref != null) { + visitor.OnInlineField (opcode, field_ref); + break; + } + + var method_ref = member as MethodReference; + if (method_ref != null) { + visitor.OnInlineMethod (opcode, method_ref); + break; + } + + throw new InvalidOperationException (); + } + break; + } + } + } + + static VariableDefinition GetVariable (ParseContext context, int index) + { + return context.Variables [index]; + } + } +} diff --git a/rocks/Mono.Cecil.Rocks/MethodBodyRocks.cs b/rocks/Mono.Cecil.Rocks/MethodBodyRocks.cs new file mode 100644 index 000000000..236b687ce --- /dev/null +++ b/rocks/Mono.Cecil.Rocks/MethodBodyRocks.cs @@ -0,0 +1,407 @@ +// +// MethodBodyRocks.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +using Mono.Cecil.Cil; + +namespace Mono.Cecil.Rocks { + +#if INSIDE_ROCKS + public +#endif + static class MethodBodyRocks { + + public static void SimplifyMacros (this MethodBody self) + { + if (self == null) + throw new ArgumentNullException ("self"); + + foreach (var instruction in self.Instructions) { + if (instruction.OpCode.OpCodeType != OpCodeType.Macro) + continue; + + switch (instruction.OpCode.Code) { + case Code.Ldarg_0: + ExpandMacro (instruction, OpCodes.Ldarg, self.GetParameter (0)); + break; + case Code.Ldarg_1: + ExpandMacro (instruction, OpCodes.Ldarg, self.GetParameter (1)); + break; + case Code.Ldarg_2: + ExpandMacro (instruction, OpCodes.Ldarg, self.GetParameter (2)); + break; + case Code.Ldarg_3: + ExpandMacro (instruction, OpCodes.Ldarg, self.GetParameter (3)); + break; + case Code.Ldloc_0: + ExpandMacro (instruction, OpCodes.Ldloc, self.Variables [0]); + break; + case Code.Ldloc_1: + ExpandMacro (instruction, OpCodes.Ldloc, self.Variables [1]); + break; + case Code.Ldloc_2: + ExpandMacro (instruction, OpCodes.Ldloc, self.Variables [2]); + break; + case Code.Ldloc_3: + ExpandMacro (instruction, OpCodes.Ldloc, self.Variables [3]); + break; + case Code.Stloc_0: + ExpandMacro (instruction, OpCodes.Stloc, self.Variables [0]); + break; + case Code.Stloc_1: + ExpandMacro (instruction, OpCodes.Stloc, self.Variables [1]); + break; + case Code.Stloc_2: + ExpandMacro (instruction, OpCodes.Stloc, self.Variables [2]); + break; + case Code.Stloc_3: + ExpandMacro (instruction, OpCodes.Stloc, self.Variables [3]); + break; + case Code.Ldarg_S: + instruction.OpCode = OpCodes.Ldarg; + break; + case Code.Ldarga_S: + instruction.OpCode = OpCodes.Ldarga; + break; + case Code.Starg_S: + instruction.OpCode = OpCodes.Starg; + break; + case Code.Ldloc_S: + instruction.OpCode = OpCodes.Ldloc; + break; + case Code.Ldloca_S: + instruction.OpCode = OpCodes.Ldloca; + break; + case Code.Stloc_S: + instruction.OpCode = OpCodes.Stloc; + break; + case Code.Ldc_I4_M1: + ExpandMacro (instruction, OpCodes.Ldc_I4, -1); + break; + case Code.Ldc_I4_0: + ExpandMacro (instruction, OpCodes.Ldc_I4, 0); + break; + case Code.Ldc_I4_1: + ExpandMacro (instruction, OpCodes.Ldc_I4, 1); + break; + case Code.Ldc_I4_2: + ExpandMacro (instruction, OpCodes.Ldc_I4, 2); + break; + case Code.Ldc_I4_3: + ExpandMacro (instruction, OpCodes.Ldc_I4, 3); + break; + case Code.Ldc_I4_4: + ExpandMacro (instruction, OpCodes.Ldc_I4, 4); + break; + case Code.Ldc_I4_5: + ExpandMacro (instruction, OpCodes.Ldc_I4, 5); + break; + case Code.Ldc_I4_6: + ExpandMacro (instruction, OpCodes.Ldc_I4, 6); + break; + case Code.Ldc_I4_7: + ExpandMacro (instruction, OpCodes.Ldc_I4, 7); + break; + case Code.Ldc_I4_8: + ExpandMacro (instruction, OpCodes.Ldc_I4, 8); + break; + case Code.Ldc_I4_S: + ExpandMacro (instruction, OpCodes.Ldc_I4, (int) (sbyte) instruction.Operand); + break; + case Code.Br_S: + instruction.OpCode = OpCodes.Br; + break; + case Code.Brfalse_S: + instruction.OpCode = OpCodes.Brfalse; + break; + case Code.Brtrue_S: + instruction.OpCode = OpCodes.Brtrue; + break; + case Code.Beq_S: + instruction.OpCode = OpCodes.Beq; + break; + case Code.Bge_S: + instruction.OpCode = OpCodes.Bge; + break; + case Code.Bgt_S: + instruction.OpCode = OpCodes.Bgt; + break; + case Code.Ble_S: + instruction.OpCode = OpCodes.Ble; + break; + case Code.Blt_S: + instruction.OpCode = OpCodes.Blt; + break; + case Code.Bne_Un_S: + instruction.OpCode = OpCodes.Bne_Un; + break; + case Code.Bge_Un_S: + instruction.OpCode = OpCodes.Bge_Un; + break; + case Code.Bgt_Un_S: + instruction.OpCode = OpCodes.Bgt_Un; + break; + case Code.Ble_Un_S: + instruction.OpCode = OpCodes.Ble_Un; + break; + case Code.Blt_Un_S: + instruction.OpCode = OpCodes.Blt_Un; + break; + case Code.Leave_S: + instruction.OpCode = OpCodes.Leave; + break; + } + } + } + + static void ExpandMacro (Instruction instruction, OpCode opcode, object operand) + { + instruction.OpCode = opcode; + instruction.Operand = operand; + } + + static void MakeMacro (Instruction instruction, OpCode opcode) + { + instruction.OpCode = opcode; + instruction.Operand = null; + } + + public static void OptimizeMacros (this MethodBody self) + { + if (self == null) + throw new ArgumentNullException ("self"); + + var method = self.Method; + + foreach (var instruction in self.Instructions) { + int index; + switch (instruction.OpCode.Code) { + case Code.Ldarg: + index = ((ParameterDefinition) instruction.Operand).Index; + if (index == -1 && instruction.Operand == self.ThisParameter) + index = 0; + else if (method.HasThis) + index++; + + switch (index) { + case 0: + MakeMacro (instruction, OpCodes.Ldarg_0); + break; + case 1: + MakeMacro (instruction, OpCodes.Ldarg_1); + break; + case 2: + MakeMacro (instruction, OpCodes.Ldarg_2); + break; + case 3: + MakeMacro (instruction, OpCodes.Ldarg_3); + break; + default: + if (index < 256) + ExpandMacro (instruction, OpCodes.Ldarg_S, instruction.Operand); + break; + } + break; + case Code.Ldloc: + index = ((VariableDefinition) instruction.Operand).Index; + switch (index) { + case 0: + MakeMacro (instruction, OpCodes.Ldloc_0); + break; + case 1: + MakeMacro (instruction, OpCodes.Ldloc_1); + break; + case 2: + MakeMacro (instruction, OpCodes.Ldloc_2); + break; + case 3: + MakeMacro (instruction, OpCodes.Ldloc_3); + break; + default: + if (index < 256) + ExpandMacro (instruction, OpCodes.Ldloc_S, instruction.Operand); + break; + } + break; + case Code.Stloc: + index = ((VariableDefinition) instruction.Operand).Index; + switch (index) { + case 0: + MakeMacro (instruction, OpCodes.Stloc_0); + break; + case 1: + MakeMacro (instruction, OpCodes.Stloc_1); + break; + case 2: + MakeMacro (instruction, OpCodes.Stloc_2); + break; + case 3: + MakeMacro (instruction, OpCodes.Stloc_3); + break; + default: + if (index < 256) + ExpandMacro (instruction, OpCodes.Stloc_S, instruction.Operand); + break; + } + break; + case Code.Ldarga: + index = ((ParameterDefinition) instruction.Operand).Index; + if (index == -1 && instruction.Operand == self.ThisParameter) + index = 0; + else if (method.HasThis) + index++; + if (index < 256) + ExpandMacro (instruction, OpCodes.Ldarga_S, instruction.Operand); + break; + case Code.Ldloca: + if (((VariableDefinition) instruction.Operand).Index < 256) + ExpandMacro (instruction, OpCodes.Ldloca_S, instruction.Operand); + break; + case Code.Ldc_I4: + int i = (int) instruction.Operand; + switch (i) { + case -1: + MakeMacro (instruction, OpCodes.Ldc_I4_M1); + break; + case 0: + MakeMacro (instruction, OpCodes.Ldc_I4_0); + break; + case 1: + MakeMacro (instruction, OpCodes.Ldc_I4_1); + break; + case 2: + MakeMacro (instruction, OpCodes.Ldc_I4_2); + break; + case 3: + MakeMacro (instruction, OpCodes.Ldc_I4_3); + break; + case 4: + MakeMacro (instruction, OpCodes.Ldc_I4_4); + break; + case 5: + MakeMacro (instruction, OpCodes.Ldc_I4_5); + break; + case 6: + MakeMacro (instruction, OpCodes.Ldc_I4_6); + break; + case 7: + MakeMacro (instruction, OpCodes.Ldc_I4_7); + break; + case 8: + MakeMacro (instruction, OpCodes.Ldc_I4_8); + break; + default: + if (i >= -128 && i < 128) + ExpandMacro (instruction, OpCodes.Ldc_I4_S, (sbyte) i); + break; + } + break; + } + } + + OptimizeBranches (self); + } + + static void OptimizeBranches (MethodBody body) + { + ComputeOffsets (body); + + foreach (var instruction in body.Instructions) { + if (instruction.OpCode.OperandType != OperandType.InlineBrTarget) + continue; + + if (OptimizeBranch (instruction)) + ComputeOffsets (body); + } + } + + static bool OptimizeBranch (Instruction instruction) + { + var offset = ((Instruction) instruction.Operand).Offset - (instruction.Offset + instruction.OpCode.Size + 4); + if (!(offset >= -128 && offset <= 127)) + return false; + + switch (instruction.OpCode.Code) { + case Code.Br: + instruction.OpCode = OpCodes.Br_S; + break; + case Code.Brfalse: + instruction.OpCode = OpCodes.Brfalse_S; + break; + case Code.Brtrue: + instruction.OpCode = OpCodes.Brtrue_S; + break; + case Code.Beq: + instruction.OpCode = OpCodes.Beq_S; + break; + case Code.Bge: + instruction.OpCode = OpCodes.Bge_S; + break; + case Code.Bgt: + instruction.OpCode = OpCodes.Bgt_S; + break; + case Code.Ble: + instruction.OpCode = OpCodes.Ble_S; + break; + case Code.Blt: + instruction.OpCode = OpCodes.Blt_S; + break; + case Code.Bne_Un: + instruction.OpCode = OpCodes.Bne_Un_S; + break; + case Code.Bge_Un: + instruction.OpCode = OpCodes.Bge_Un_S; + break; + case Code.Bgt_Un: + instruction.OpCode = OpCodes.Bgt_Un_S; + break; + case Code.Ble_Un: + instruction.OpCode = OpCodes.Ble_Un_S; + break; + case Code.Blt_Un: + instruction.OpCode = OpCodes.Blt_Un_S; + break; + case Code.Leave: + instruction.OpCode = OpCodes.Leave_S; + break; + } + + return true; + } + + static void ComputeOffsets (MethodBody body) + { + var offset = 0; + foreach (var instruction in body.Instructions) { + instruction.Offset = offset; + offset += instruction.GetSize (); + } + } + } +} diff --git a/rocks/Mono.Cecil.Rocks/MethodDefinitionRocks.cs b/rocks/Mono.Cecil.Rocks/MethodDefinitionRocks.cs new file mode 100644 index 000000000..c011af26c --- /dev/null +++ b/rocks/Mono.Cecil.Rocks/MethodDefinitionRocks.cs @@ -0,0 +1,88 @@ +// +// MethodDefinitionRocks.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace Mono.Cecil.Rocks { + +#if INSIDE_ROCKS + public +#endif + static class MethodDefinitionRocks { + + public static MethodDefinition GetBaseMethod (this MethodDefinition self) + { + if (self == null) + throw new ArgumentNullException ("self"); + if (!self.IsVirtual) + return self; + + var base_type = ResolveBaseType (self.DeclaringType); + while (base_type != null) { + var @base = GetMatchingMethod (base_type, self); + if (@base != null) + return @base; + + base_type = ResolveBaseType (base_type); + } + + return self; + } + + public static MethodDefinition GetOriginalBaseMethod (this MethodDefinition self) + { + if (self == null) + throw new ArgumentNullException ("self"); + + while (true) { + var @base = self.GetBaseMethod (); + if (@base == self) + return self; + + self = @base; + } + } + + static TypeDefinition ResolveBaseType (TypeDefinition type) + { + if (type == null) + return null; + + var base_type = type.BaseType; + if (base_type == null) + return null; + + return base_type.Resolve (); + } + + static MethodDefinition GetMatchingMethod (TypeDefinition type, MethodDefinition method) + { + return MetadataResolver.GetMethod (type.Methods, method); + } + } +} diff --git a/rocks/Mono.Cecil.Rocks/ModuleDefinitionRocks.cs b/rocks/Mono.Cecil.Rocks/ModuleDefinitionRocks.cs new file mode 100644 index 000000000..db77417ae --- /dev/null +++ b/rocks/Mono.Cecil.Rocks/ModuleDefinitionRocks.cs @@ -0,0 +1,50 @@ +// +// ModuleDefinitionRocks.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Mono.Cecil.Rocks { + +#if INSIDE_ROCKS + public +#endif + static class ModuleDefinitionRocks { + + public static IEnumerable GetAllTypes (this ModuleDefinition self) + { + if (self == null) + throw new ArgumentNullException ("self"); + + // it was fun to write, but we need a somewhat less convoluted implementation + return self.Types.SelectMany ( + Functional.Y> (f => type => type.NestedTypes.SelectMany (f).Prepend (type))); + } + } +} diff --git a/rocks/Mono.Cecil.Rocks/ParameterReferenceRocks.cs b/rocks/Mono.Cecil.Rocks/ParameterReferenceRocks.cs new file mode 100644 index 000000000..554bdb909 --- /dev/null +++ b/rocks/Mono.Cecil.Rocks/ParameterReferenceRocks.cs @@ -0,0 +1,11 @@ + +namespace Mono.Cecil.Rocks { + + public static class ParameterReferenceRocks { + + public static int GetSequence (this ParameterReference self) + { + return self.Index + 1; + } + } +} diff --git a/rocks/Mono.Cecil.Rocks/SecurityDeclarationRocks.cs b/rocks/Mono.Cecil.Rocks/SecurityDeclarationRocks.cs new file mode 100644 index 000000000..7b1f82dae --- /dev/null +++ b/rocks/Mono.Cecil.Rocks/SecurityDeclarationRocks.cs @@ -0,0 +1,174 @@ +// +// SecurityDeclarationRocks.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +#if !SILVERLIGHT && !CF + +using System; +using System.Security; +using SSP = System.Security.Permissions; + +namespace Mono.Cecil.Rocks { + +#if INSIDE_ROCKS + public +#endif + static class SecurityDeclarationRocks { + + public static PermissionSet ToPermissionSet (this SecurityDeclaration self) + { + if (self == null) + throw new ArgumentNullException ("self"); + + PermissionSet set; + if (TryProcessPermissionSetAttribute (self, out set)) + return set; + + return CreatePermissionSet (self); + } + + static bool TryProcessPermissionSetAttribute (SecurityDeclaration declaration, out PermissionSet set) + { + set = null; + + if (!declaration.HasSecurityAttributes && declaration.SecurityAttributes.Count != 1) + return false; + + var security_attribute = declaration.SecurityAttributes [0]; + if (!security_attribute.AttributeType.IsTypeOf ("System.Security.Permissions", "PermissionSetAttribute")) + return false; + + var attribute = new SSP.PermissionSetAttribute ((SSP.SecurityAction) declaration.Action); + + var named_argument = security_attribute.Properties [0]; + string value = (string) named_argument.Argument.Value; + switch (named_argument.Name) { + case "XML": + attribute.XML = value; + break; + case "Name": + attribute.Name = value; + break; + default: + throw new NotImplementedException (named_argument.Name); + } + + set = attribute.CreatePermissionSet (); + return true; + } + + static PermissionSet CreatePermissionSet (SecurityDeclaration declaration) + { + var set = new PermissionSet (SSP.PermissionState.None); + + foreach (var attribute in declaration.SecurityAttributes) { + var permission = CreatePermission (declaration, attribute); + set.AddPermission (permission); + } + + return set; + } + + static IPermission CreatePermission (SecurityDeclaration declaration, SecurityAttribute attribute) + { + var attribute_type = Type.GetType (attribute.AttributeType.FullName); + if (attribute_type == null) + throw new ArgumentException ("attribute"); + + var security_attribute = CreateSecurityAttribute (attribute_type, declaration); + if (security_attribute == null) + throw new InvalidOperationException (); + + CompleteSecurityAttribute (security_attribute, attribute); + + return security_attribute.CreatePermission (); + } + + static void CompleteSecurityAttribute (SSP.SecurityAttribute security_attribute, SecurityAttribute attribute) + { + if (attribute.HasFields) + CompleteSecurityAttributeFields (security_attribute, attribute); + + if (attribute.HasProperties) + CompleteSecurityAttributeProperties (security_attribute, attribute); + } + + static void CompleteSecurityAttributeFields (SSP.SecurityAttribute security_attribute, SecurityAttribute attribute) + { + var type = security_attribute.GetType (); + + foreach (var named_argument in attribute.Fields) + type.GetField (named_argument.Name).SetValue (security_attribute, named_argument.Argument.Value); + } + + static void CompleteSecurityAttributeProperties (SSP.SecurityAttribute security_attribute, SecurityAttribute attribute) + { + var type = security_attribute.GetType (); + + foreach (var named_argument in attribute.Properties) + type.GetProperty (named_argument.Name).SetValue (security_attribute, named_argument.Argument.Value, null); + } + + static SSP.SecurityAttribute CreateSecurityAttribute (Type attribute_type, SecurityDeclaration declaration) + { + SSP.SecurityAttribute security_attribute; + try { + security_attribute = (SSP.SecurityAttribute) Activator.CreateInstance ( + attribute_type, new object [] { (SSP.SecurityAction) declaration.Action }); + } catch (MissingMethodException) { + security_attribute = (SSP.SecurityAttribute) Activator.CreateInstance (attribute_type, new object [0]); + } + + return security_attribute; + } + + public static SecurityDeclaration ToSecurityDeclaration (this PermissionSet self, SecurityAction action, ModuleDefinition module) + { + if (self == null) + throw new ArgumentNullException ("self"); + if (module == null) + throw new ArgumentNullException ("module"); + + var declaration = new SecurityDeclaration (action); + + var attribute = new SecurityAttribute ( + module.TypeSystem.LookupType ("System.Security.Permissions", "PermissionSetAttribute")); + + attribute.Properties.Add ( + new CustomAttributeNamedArgument ( + "XML", + new CustomAttributeArgument ( + module.TypeSystem.String, self.ToXml ().ToString ()))); + + declaration.SecurityAttributes.Add (attribute); + + return declaration; + } + } +} + +#endif diff --git a/rocks/Mono.Cecil.Rocks/TypeDefinitionRocks.cs b/rocks/Mono.Cecil.Rocks/TypeDefinitionRocks.cs new file mode 100644 index 000000000..f5173af50 --- /dev/null +++ b/rocks/Mono.Cecil.Rocks/TypeDefinitionRocks.cs @@ -0,0 +1,83 @@ +// +// TypeDefinitionRocks.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Mono.Cecil.Rocks { + +#if INSIDE_ROCKS + public +#endif + static class TypeDefinitionRocks { + + public static IEnumerable GetConstructors (this TypeDefinition self) + { + if (self == null) + throw new ArgumentNullException ("self"); + + if (!self.HasMethods) + return Empty.Array; + + return self.Methods.Where (method => method.IsConstructor); + } + + public static MethodDefinition GetStaticConstructor (this TypeDefinition self) + { + if (self == null) + throw new ArgumentNullException ("self"); + + if (!self.HasMethods) + return null; + + return self.GetConstructors ().FirstOrDefault (ctor => ctor.IsStatic); + } + + public static IEnumerable GetMethods (this TypeDefinition self) + { + if (self == null) + throw new ArgumentNullException ("self"); + + if (!self.HasMethods) + return Empty.Array; + + return self.Methods.Where (method => !method.IsConstructor); + } + + public static TypeReference GetEnumUnderlyingType (this TypeDefinition self) + { + if (self == null) + throw new ArgumentNullException ("self"); + if (!self.IsEnum) + throw new ArgumentException (); + + return Mixin.GetEnumUnderlyingType (self); + } + } +} diff --git a/rocks/Mono.Cecil.Rocks/TypeReferenceRocks.cs b/rocks/Mono.Cecil.Rocks/TypeReferenceRocks.cs new file mode 100644 index 000000000..0ceb51b5c --- /dev/null +++ b/rocks/Mono.Cecil.Rocks/TypeReferenceRocks.cs @@ -0,0 +1,107 @@ +// +// TypeReferenceRocks.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Mono.Cecil.Rocks { + +#if INSIDE_ROCKS + public +#endif + static class TypeReferenceRocks { + + public static ArrayType MakeArrayType (this TypeReference self) + { + return new ArrayType (self); + } + + public static ArrayType MakeArrayType (this TypeReference self, int rank) + { + if (rank == 0) + throw new ArgumentOutOfRangeException ("rank"); + + var array = new ArrayType (self); + + for (int i = 1; i < rank; i++) + array.Dimensions.Add (new ArrayDimension ()); + + return array; + } + + public static PointerType MakePointerType (this TypeReference self) + { + return new PointerType (self); + } + + public static ByReferenceType MakeByReferenceType (this TypeReference self) + { + return new ByReferenceType (self); + } + + public static OptionalModifierType MakeOptionalModifierType (this TypeReference self, TypeReference modifierType) + { + return new OptionalModifierType (modifierType, self); + } + + public static RequiredModifierType MakeRequiredModifierType (this TypeReference self, TypeReference modifierType) + { + return new RequiredModifierType (modifierType, self); + } + + public static GenericInstanceType MakeGenericInstanceType (this TypeReference self, params TypeReference [] arguments) + { + if (self == null) + throw new ArgumentNullException ("self"); + if (arguments == null) + throw new ArgumentNullException ("arguments"); + if (arguments.Length == 0) + throw new ArgumentException (); + if (self.GenericParameters.Count != arguments.Length) + throw new ArgumentException (); + + var instance = new GenericInstanceType (self); + + foreach (var argument in arguments) + instance.GenericArguments.Add (argument); + + return instance; + } + + public static PinnedType MakePinnedType (this TypeReference self) + { + return new PinnedType (self); + } + + public static SentinelType MakeSentinelType (this TypeReference self) + { + return new SentinelType (self); + } + } +} diff --git a/rocks/Test/.gitignore b/rocks/Test/.gitignore new file mode 100644 index 000000000..3629e370c --- /dev/null +++ b/rocks/Test/.gitignore @@ -0,0 +1,7 @@ +bin +obj +*.suo +*.user +*.pidb +*.userprefs +*.xml diff --git a/rocks/Test/Mono.Cecil.Rocks.Tests.csproj b/rocks/Test/Mono.Cecil.Rocks.Tests.csproj new file mode 100644 index 000000000..a8a8c912b --- /dev/null +++ b/rocks/Test/Mono.Cecil.Rocks.Tests.csproj @@ -0,0 +1,106 @@ + + + + net_4_0_Debug + AnyCPU + 9.0.30729 + 2.0 + {C6CFD7E1-B855-44DC-B4CE-9CD72984AF52} + Library + Properties + Mono.Cecil.Rocks.Tests + Mono.Cecil.Rocks.Tests + 512 + + + true + full + false + bin\net_3_5_Debug\ + DEBUG;TRACE;NET_3_5 + prompt + 4 + v3.5 + + + pdbonly + true + bin\net_3_5_Release\ + TRACE;NET_3_5 + prompt + 4 + v3.5 + + + true + full + false + bin\net_4_0_Debug\ + DEBUG;TRACE;NET_3_5;NET_4_0 + prompt + 4 + v4.0 + + + pdbonly + true + bin\net_4_0_Release\ + TRACE;NET_3_5;NET_4_0 + prompt + 4 + v4.0 + + + + False + ..\..\Test\libs\nunit-2.4.8\nunit.core.dll + + + False + ..\..\Test\libs\nunit-2.4.8\nunit.core.interfaces.dll + + + False + ..\..\Test\libs\nunit-2.4.8\nunit.framework.dll + + + + 3.5 + + + + + {D68133BD-1E63-496E-9EDE-4FBDBF77B486} + Mono.Cecil + + + {A47B1F49-A81A-43E8-BE6B-DD28AF2C4055} + Mono.Cecil.Tests + + + {FBC6DD59-D09D-499C-B03C-99C1C78FF2AC} + Mono.Cecil.Rocks + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/rocks/Test/Mono.Cecil.Tests/Addin.cs b/rocks/Test/Mono.Cecil.Tests/Addin.cs new file mode 100644 index 000000000..5a9f85f2a --- /dev/null +++ b/rocks/Test/Mono.Cecil.Tests/Addin.cs @@ -0,0 +1,8 @@ +using NUnit.Core.Extensibility; + +namespace Mono.Cecil.Tests { + + [NUnitAddin] + public class CecilRocksAddin : CecilTestAddin { + } +} diff --git a/rocks/Test/Mono.Cecil.Tests/MethodDefinitionRocksTests.cs b/rocks/Test/Mono.Cecil.Tests/MethodDefinitionRocksTests.cs new file mode 100644 index 000000000..2cfe0142a --- /dev/null +++ b/rocks/Test/Mono.Cecil.Tests/MethodDefinitionRocksTests.cs @@ -0,0 +1,53 @@ +using System.Linq; + +using NUnit.Framework; + +using Mono.Cecil.Rocks; + +namespace Mono.Cecil.Tests { + + [TestFixture] + public class MethodDefinitionRocksTests : BaseTestFixture { + + abstract class Foo { + public abstract void DoFoo (); + } + + class Bar : Foo { + public override void DoFoo () + { + } + } + + class Baz : Bar { + public override void DoFoo () + { + } + } + + [Test] + public void GetBaseMethod () + { + var baz = typeof (Baz).ToDefinition (); + var baz_dofoo = baz.GetMethod ("DoFoo"); + + var @base = baz_dofoo.GetBaseMethod (); + Assert.AreEqual ("Bar", @base.DeclaringType.Name); + + @base = @base.GetBaseMethod (); + Assert.AreEqual ("Foo", @base.DeclaringType.Name); + + Assert.AreEqual (@base, @base.GetBaseMethod ()); + } + + [Test] + public void GetOriginalBaseMethod () + { + var baz = typeof (Baz).ToDefinition (); + var baz_dofoo = baz.GetMethod ("DoFoo"); + + var @base = baz_dofoo.GetOriginalBaseMethod (); + Assert.AreEqual ("Foo", @base.DeclaringType.Name); + } + } +} diff --git a/rocks/Test/Mono.Cecil.Tests/ModuleDefinitionRocksTests.cs b/rocks/Test/Mono.Cecil.Tests/ModuleDefinitionRocksTests.cs new file mode 100644 index 000000000..f172b404e --- /dev/null +++ b/rocks/Test/Mono.Cecil.Tests/ModuleDefinitionRocksTests.cs @@ -0,0 +1,27 @@ +using System.Linq; + +using NUnit.Framework; + +using Mono.Cecil.Rocks; + +namespace Mono.Cecil.Tests { + + [TestFixture] + public class ModuleDefinitionRocksTests : BaseTestFixture { + + [TestCSharp ("Types.cs")] + public void GetAllTypesTest (ModuleDefinition module) + { + var sequence = new [] { + module.GetType (""), + module.GetType ("Foo"), + module.GetType ("Foo/Bar"), + module.GetType ("Foo/Gazonk"), + module.GetType ("Foo/Gazonk/Baz"), + module.GetType ("Pan"), + }; + + Assert.IsTrue (sequence.SequenceEqual (module.GetAllTypes ())); + } + } +} diff --git a/rocks/Test/Mono.Cecil.Tests/SecurityDeclarationRocksTests.cs b/rocks/Test/Mono.Cecil.Tests/SecurityDeclarationRocksTests.cs new file mode 100644 index 000000000..e7efba127 --- /dev/null +++ b/rocks/Test/Mono.Cecil.Tests/SecurityDeclarationRocksTests.cs @@ -0,0 +1,63 @@ +using System.Security.Permissions; + +using NUnit.Framework; + +using Mono.Cecil.Rocks; + +namespace Mono.Cecil.Tests { + + [TestFixture] + public class SecurityDeclarationRocksTests : BaseTestFixture { + + [TestModule ("decsec-xml.dll")] + public void ToPermissionSetFromPermissionSetAttribute (ModuleDefinition module) + { + var type = module.GetType ("SubLibrary"); + + Assert.IsTrue (type.HasSecurityDeclarations); + Assert.AreEqual (1, type.SecurityDeclarations.Count); + + var declaration = type.SecurityDeclarations [0]; + + var permission_set = declaration.ToPermissionSet (); + + Assert.IsNotNull (permission_set); + + string permission_set_value = "\r\n\r\n\r\n"; + + permission_set_value = string.Format (permission_set_value, typeof (SecurityPermission).AssemblyQualifiedName); + + Assert.AreEqual (Normalize (permission_set_value), Normalize (permission_set.ToXml ().ToString ())); + } + + [TestModule ("decsec-att.dll")] + public void ToPermissionSetFromSecurityAttribute (ModuleDefinition module) + { + var type = module.GetType ("SubLibrary"); + + Assert.IsTrue (type.HasSecurityDeclarations); + Assert.AreEqual (1, type.SecurityDeclarations.Count); + + var declaration = type.SecurityDeclarations [0]; + + var permission_set = declaration.ToPermissionSet (); + + Assert.IsNotNull (permission_set); + + string permission_set_value = "\r\n\r\n\r\n"; + + permission_set_value = string.Format (permission_set_value, typeof (SecurityPermission).AssemblyQualifiedName); + + Assert.AreEqual (Normalize (permission_set_value), Normalize (permission_set.ToXml ().ToString ())); + } + + static string Normalize (string s) + { + return s.Replace ("\n", "").Replace ("\r", ""); + } + } +} diff --git a/rocks/Test/Mono.Cecil.Tests/TypeDefinitionRocksTests.cs b/rocks/Test/Mono.Cecil.Tests/TypeDefinitionRocksTests.cs new file mode 100644 index 000000000..7bd43cf7e --- /dev/null +++ b/rocks/Test/Mono.Cecil.Tests/TypeDefinitionRocksTests.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Mono.Cecil.Rocks; + +using NUnit.Framework; + +namespace Mono.Cecil.Tests { + + [TestFixture] + public class TypeDefinitionRocksTests { + + class Foo { + + static Foo () + { + } + + public Foo (int a) + { + } + + public Foo (int a, string s) + { + } + + public static void Bar () + { + } + + void Baz () + { + } + } + + [Test] + public void GetConstructors () + { + var foo = typeof (Foo).ToDefinition (); + var ctors = foo.GetConstructors ().Select (ctor => ctor.FullName); + + var expected = new [] { + "System.Void Mono.Cecil.Tests.TypeDefinitionRocksTests/Foo::.cctor()", + "System.Void Mono.Cecil.Tests.TypeDefinitionRocksTests/Foo::.ctor(System.Int32)", + "System.Void Mono.Cecil.Tests.TypeDefinitionRocksTests/Foo::.ctor(System.Int32,System.String)", + }; + + AssertSet (expected, ctors); + } + + static void AssertSet (IEnumerable expected, IEnumerable actual) + { + Assert.IsFalse (expected.Except (actual).Any ()); + Assert.IsTrue (expected.Intersect (actual).SequenceEqual (expected)); + } + + [Test] + public void GetStaticConstructor () + { + var foo = typeof (Foo).ToDefinition (); + var cctor = foo.GetStaticConstructor (); + + Assert.IsNotNull (cctor); + Assert.AreEqual ("System.Void Mono.Cecil.Tests.TypeDefinitionRocksTests/Foo::.cctor()", cctor.FullName); + } + + [Test] + public void GetMethods () + { + var foo = typeof (Foo).ToDefinition (); + var methods = foo.GetMethods ().ToArray (); + + Assert.AreEqual (2, methods.Length); + Assert.AreEqual ("System.Void Mono.Cecil.Tests.TypeDefinitionRocksTests/Foo::Bar()", methods [0].FullName); + Assert.AreEqual ("System.Void Mono.Cecil.Tests.TypeDefinitionRocksTests/Foo::Baz()", methods [1].FullName); + } + + enum Pan : byte { + Pin, + Pon, + } + + [Test] + public void GetEnumUnderlyingType () + { + var pan = typeof (Pan).ToDefinition (); + + Assert.IsNotNull (pan); + Assert.IsTrue (pan.IsEnum); + + var underlying_type = pan.GetEnumUnderlyingType (); + Assert.IsNotNull (underlying_type); + + Assert.AreEqual ("System.Byte", underlying_type.FullName); + } + } +} \ No newline at end of file diff --git a/rocks/Test/Mono.Cecil.Tests/TypeReferenceRocksTests.cs b/rocks/Test/Mono.Cecil.Tests/TypeReferenceRocksTests.cs new file mode 100644 index 000000000..3845eaa55 --- /dev/null +++ b/rocks/Test/Mono.Cecil.Tests/TypeReferenceRocksTests.cs @@ -0,0 +1,124 @@ +using System; + +using Mono.Cecil.Rocks; + +using NUnit.Framework; + +namespace Mono.Cecil.Tests { + + [TestFixture] + public class TypeReferenceRocksTests { + + [Test] + public void MakeArrayType () + { + var @string = GetTypeReference (typeof (string)); + + var string_array = @string.MakeArrayType (); + + Assert.IsInstanceOfType (typeof (ArrayType), string_array); + Assert.AreEqual (1, string_array.Rank); + } + + [Test] + public void MakeArrayTypeRank () + { + var @string = GetTypeReference (typeof (string)); + + var string_array = @string.MakeArrayType (3); + + Assert.IsInstanceOfType (typeof (ArrayType), string_array); + Assert.AreEqual (3, string_array.Rank); + } + + [Test] + public void MakePointerType () + { + var @string = GetTypeReference (typeof (string)); + + var string_ptr = @string.MakePointerType (); + + Assert.IsInstanceOfType (typeof (PointerType), string_ptr); + } + + [Test] + public void MakeByReferenceType () + { + var @string = GetTypeReference (typeof (string)); + + var string_byref = @string.MakeByReferenceType (); + + Assert.IsInstanceOfType (typeof (ByReferenceType), string_byref); + } + + class OptionalModifier {} + + [Test] + public void MakeOptionalModifierType () + { + var @string = GetTypeReference (typeof (string)); + var modopt = GetTypeReference (typeof (OptionalModifier)); + + var string_modopt = @string.MakeOptionalModifierType (modopt); + + Assert.IsInstanceOfType (typeof (OptionalModifierType), string_modopt); + Assert.AreEqual (modopt, string_modopt.ModifierType); + } + + class RequiredModifier { } + + [Test] + public void MakeRequiredModifierType () + { + var @string = GetTypeReference (typeof (string)); + var modreq = GetTypeReference (typeof (RequiredModifierType)); + + var string_modreq = @string.MakeRequiredModifierType (modreq); + + Assert.IsInstanceOfType (typeof (RequiredModifierType), string_modreq); + Assert.AreEqual (modreq, string_modreq.ModifierType); + } + + [Test] + public void MakePinnedType () + { + var byte_array = GetTypeReference (typeof (byte [])); + + var pinned_byte_array = byte_array.MakePinnedType (); + + Assert.IsInstanceOfType (typeof (PinnedType), pinned_byte_array); + } + + [Test] + public void MakeSentinelType () + { + var @string = GetTypeReference (typeof (string)); + + var string_sentinel = @string.MakeSentinelType (); + + Assert.IsInstanceOfType (typeof (SentinelType), string_sentinel); + } + + class Foo {} + + [Test] + public void MakeGenericInstanceType () + { + var foo = GetTypeReference (typeof (Foo<,>)); + var @string = GetTypeReference (typeof (string)); + var @int = GetTypeReference (typeof (int)); + + var foo_string_int = foo.MakeGenericInstanceType (@string, @int); + + Assert.IsInstanceOfType (typeof (GenericInstanceType), foo_string_int); + Assert.AreEqual (2, foo_string_int.GenericArguments.Count); + Assert.AreEqual (@string, foo_string_int.GenericArguments [0]); + Assert.AreEqual (@int, foo_string_int.GenericArguments [1]); + } + + static TypeReference GetTypeReference (Type type) + { + return ModuleDefinition.ReadModule (typeof (TypeReferenceRocksTests).Module.FullyQualifiedName).Import (type); + } + } +} \ No newline at end of file diff --git a/rocks/Test/Resources/assemblies/decsec-att.dll b/rocks/Test/Resources/assemblies/decsec-att.dll new file mode 100644 index 0000000000000000000000000000000000000000..e9ac355408f5423bfea500f79051791f4d204aed GIT binary patch literal 4096 zcmeHKPiz!b82`<7w^^#KfXbg3aGIh)QZ_5J6cW&-e<(;xE4!^mjdXVQu^pM6X=Y}z zRikU7Mh+$%jF=dE;^4s;4oxH^CMJ5tvnNBmdhkXJ2kY;9v(u%}D4HHH;oH9N|NGwe zeecb@>G&%b(FP#RvAhgiB^4-W{P(CqbJvsCy0En2diPah?0R=;)(OqIz^?{Y&9p7g z^CPpY%%JX>j%N-}6wR7nQMt~}j$O^rlOw>G(S|R7x^yyG?FLfa4;fj2e`t@j-#krf zauhfOnIx$=Z*n?+p=fYWFVKdV*rymFB#rDJC<(!>bhcD422j ziFcOr@kAiaMQT1GU6T4t4ypBy^{Jl81z}**q;o5fk&Wu$xD5(yNG?#WPe+~W42=@2 zi{myZ0E4%Qn!PA}B}i^5WH4(2e`Ekdl>Y%bw(i-P+RY?8_H=ApVYzVeg+ZekRdPJP zFPG2t=Lhx;$RZiI#D}?P&%3}^q-o)cQQ&yhP&~e7J<_6{sUnuhb63$bI(1^0^he5l zJj6YNu3x4sK$S6C0yc8FpF)GI@p8`E|iMn7#eyhwaO#J;=FpABL zGm33^hPaEh2+rYATqAx0Kj-!3gd6G?gX(m7eW*+eq^?>_EDKJK!c|sXGA! zy$Q=r822l6S3QS{vO{I>wW26jab1i#<-iISP^^~|wieoc;5ua#7s5!@Fj0O(*%6NU zK5};C2N<-1rY%=gc0F*Sh1{eHYEBqBz84}s0kueq=lt~pWMXev7{b7@&ywdzK+nVJm#l6mL*%c-%; zx!-OzZe|ye{r0WbrnmRqxWL1frIV2{4P#ShnmF6|B4;!{h&!=nwJXXss_iwCUiO;P zDv<6Rkq3moUUR7KM)g1)@l-tuEVtL3te0KKKB*Q;{yF6xDGv--{dWI>XAkY~Q~863 zHXEf>=ag5oJgcfILww;HSwlZOz)m@rGH0E*c*v8^HXO0Kh zIqTT^2{b-#-Y@b%EedZ6cQ+*W5O8M54~AWL+;TkVr$QB&U#h4z>!q@g)`Xi}Ct3_={yM>5;KBXA0q?dSk z8_X%9mqUGZjYt=@Paesy4`uS;ZJFZSWaVM59>Ugf=2op^(l^f+Z_9U@z5%^kx#W41 zw+2waBlMSQBJJxjcbEOL_#L7cuR?4yg5bTnu80vT^pP(pV7Ja~jP|OYImD{xu%NT6 zVwO>%AHm~#or$JiIw0#LHHma@>-FjSCK<JANyZ%^Lxh}FGt!v+RP|K@A<{)3AQni zO*@|jnuV|sQYl((orI#uBahOGr$Mzc4h%+`HlhW`(1@$Jq3AEGTI|rc;yGdss;{8~ z(-BsO-*sX8q_b0v{i(3q=`6!a!(V&G&@G&|aaoNuLuMRPbrR1am1yGH^NAMLA2v3# zw(1kK<~UED)b)%;)|(Wu2fB!fT``D`3RL(wb`JBocP%qOrd$lHJd$SM`B<^cqGg`m z$U7LF^;Sxbb+(G8LT<*+`G#Lcrj(1jQ=W%0!^fqP8`ybk+{+h?z|Pr@9hA=n+`n8Y zu%d;M5mQpQY{&95mcMSBmfB!Zuug~8^zDtSOD_y>XJa=-#v|s`3pn&!7*OS2U5nK>3mtl+@AQo8y3d)j5vnBtDcpBG1hhy~^~0 zLCgwOQhE!|Ub*{uPBL@WFvD4^ob4!y1%=~pAfM!QvPyvx!z@?$be0obDYi}Qku~F-Ii-9R%h~Ux z2mN$G={+CWV@G<&^TmqLV~^HfblUY(7!5K@GCQA#F4j=2c#1)f{`DY%eF#sT2mS%T C7 + + + net_4_0_Debug + AnyCPU + 9.0.30729 + 2.0 + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD} + Library + Properties + Mono.Cecil.Mdb + Mono.Cecil.Mdb + 512 + true + ..\..\mono.snk + + + true + full + false + ..\..\bin\net_2_0_Debug\ + DEBUG;TRACE;CECIL + prompt + 4 + v2.0 + + + pdbonly + true + ..\..\bin\net_2_0_Release\ + TRACE;CECIL + prompt + 4 + v2.0 + + + true + full + false + ..\..\bin\net_3_5_Debug\ + DEBUG;TRACE;CECIL;NET_3_5 + prompt + 4 + v3.5 + + + pdbonly + true + ..\..\bin\net_3_5_Release\ + TRACE;CECIL;NET_3_5 + prompt + 4 + v3.5 + + + true + full + false + ..\..\bin\net_4_0_Debug\ + DEBUG;TRACE;CECIL;NET_3_5;NET_4_0 + prompt + 4 + v4.0 + + + pdbonly + true + ..\..\bin\net_4_0_Release\ + TRACE;CECIL;NET_3_5;NET_4_0 + prompt + 4 + v4.0 + + + + + + + + + + {D68133BD-1E63-496E-9EDE-4FBDBF77B486} + Mono.Cecil + + + + + + + + + + + + + + \ No newline at end of file diff --git a/symbols/mdb/Mono.Cecil.Mdb/AssemblyInfo.cs b/symbols/mdb/Mono.Cecil.Mdb/AssemblyInfo.cs new file mode 100644 index 000000000..a08113a31 --- /dev/null +++ b/symbols/mdb/Mono.Cecil.Mdb/AssemblyInfo.cs @@ -0,0 +1,41 @@ +// +// AssemblyInfo.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Reflection; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle ("Mono.Cecil.Mdb")] +[assembly: AssemblyProduct ("Mono.Cecil")] +[assembly: AssemblyCopyright ("Copyright © 2008 - 2010 Jb Evain")] + +[assembly: CLSCompliant (false)] +[assembly: ComVisible (false)] + +[assembly: AssemblyVersion ("0.9.4.0")] +[assembly: AssemblyFileVersion ("0.9.4.0")] diff --git a/symbols/mdb/Mono.Cecil.Mdb/MdbReader.cs b/symbols/mdb/Mono.Cecil.Mdb/MdbReader.cs new file mode 100644 index 000000000..0198a7164 --- /dev/null +++ b/symbols/mdb/Mono.Cecil.Mdb/MdbReader.cs @@ -0,0 +1,213 @@ +// +// MdbReader.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Generic; +using System.IO; + +using Mono.Cecil.Cil; +using Mono.Collections.Generic; +using Mono.CompilerServices.SymbolWriter; + +namespace Mono.Cecil.Mdb { + + public class MdbReaderProvider : ISymbolReaderProvider { + + public ISymbolReader GetSymbolReader (ModuleDefinition module, string fileName) + { + return new MdbReader (MonoSymbolFile.ReadSymbolFile (module, fileName)); + } + + public ISymbolReader GetSymbolReader (ModuleDefinition module, Stream symbolStream) + { + throw new NotImplementedException (); + } + } + + public class MdbReader : ISymbolReader { + + readonly MonoSymbolFile symbol_file; + readonly Dictionary documents; + + public MdbReader (MonoSymbolFile symFile) + { + symbol_file = symFile; + documents = new Dictionary (); + } + + public bool ProcessDebugHeader (ImageDebugDirectory directory, byte [] header) + { + return true; + } + + public void Read (MethodBody body, InstructionMapper mapper) + { + var method_token = body.Method.MetadataToken; + var entry = symbol_file.GetMethodByToken (method_token.ToInt32 ()); + if (entry == null) + return; + + var scopes = ReadScopes (entry, body, mapper); + ReadLineNumbers (entry, mapper); + ReadLocalVariables (entry, body, scopes); + } + + static void ReadLocalVariables (MethodEntry entry, MethodBody body, Scope [] scopes) + { + var locals = entry.GetLocals (); + foreach (var local in locals) { + var variable = body.Variables [local.Index]; + variable.Name = local.Name; + + var index = local.BlockIndex; + if (index < 0 || index >= scopes.Length) + continue; + + var scope = scopes [index]; + if (scope == null) + continue; + + scope.Variables.Add (variable); + } + } + + void ReadLineNumbers (MethodEntry entry, InstructionMapper mapper) + { + Document document = null; + var table = entry.GetLineNumberTable (); + + foreach (var line in table.LineNumbers) { + var instruction = mapper (line.Offset); + if (instruction == null) + continue; + + if (document == null) + document = GetDocument (entry.CompileUnit.SourceFile); + + instruction.SequencePoint = new SequencePoint (document) { + StartLine = line.Row, + EndLine = line.Row, + }; + } + } + + Document GetDocument (SourceFileEntry file) + { + var file_name = file.FileName; + + Document document; + if (documents.TryGetValue (file_name, out document)) + return document; + + document = new Document (file_name); + documents.Add (file_name, document); + + return document; + } + + static Scope [] ReadScopes (MethodEntry entry, MethodBody body, InstructionMapper mapper) + { + var blocks = entry.GetCodeBlocks (); + var scopes = new Scope [blocks.Length]; + + foreach (var block in blocks) { + if (block.BlockType != CodeBlockEntry.Type.Lexical) + continue; + + var scope = new Scope (); + scope.Start = mapper (block.StartOffset); + scope.End = mapper (block.EndOffset); + + scopes [block.Index] = scope; + + if (body.Scope == null) + body.Scope = scope; + + if (!AddScope (body.Scope, scope)) + body.Scope = scope; + } + + return scopes; + } + + static bool AddScope (Scope provider, Scope scope) + { + foreach (var sub_scope in provider.Scopes) { + if (AddScope (sub_scope, scope)) + return true; + + if (scope.Start.Offset >= sub_scope.Start.Offset && scope.End.Offset <= sub_scope.End.Offset) { + sub_scope.Scopes.Add (scope); + return true; + } + } + + return false; + } + + public void Read (MethodSymbols symbols) + { + var entry = symbol_file.GetMethodByToken (symbols.MethodToken.ToInt32 ()); + if (entry == null) + return; + + ReadLineNumbers (entry, symbols); + ReadLocalVariables (entry, symbols); + } + + void ReadLineNumbers (MethodEntry entry, MethodSymbols symbols) + { + var table = entry.GetLineNumberTable (); + var lines = table.LineNumbers; + + var instructions = symbols.instructions = new Collection (lines.Length); + + for (int i = 0; i < lines.Length; i++) { + var line = lines [i]; + + instructions.Add (new InstructionSymbol (line.Offset, new SequencePoint (GetDocument (entry.CompileUnit.SourceFile)) { + StartLine = line.Row, + EndLine = line.Row, + })); + } + } + + static void ReadLocalVariables (MethodEntry entry, MethodSymbols symbols) + { + foreach (var local in entry.GetLocals ()) { + var variable = symbols.Variables [local.Index]; + variable.Name = local.Name; + } + } + + public void Dispose () + { + symbol_file.Dispose (); + } + } +} diff --git a/symbols/mdb/Mono.Cecil.Mdb/MdbWriter.cs b/symbols/mdb/Mono.Cecil.Mdb/MdbWriter.cs new file mode 100644 index 000000000..54362ec3c --- /dev/null +++ b/symbols/mdb/Mono.Cecil.Mdb/MdbWriter.cs @@ -0,0 +1,251 @@ +// +// MdbWriter.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Generic; +using System.IO; + +using Mono.Cecil.Cil; +using Mono.Collections.Generic; +using Mono.CompilerServices.SymbolWriter; + +namespace Mono.Cecil.Mdb { + +#if !READ_ONLY + public class MdbWriterProvider : ISymbolWriterProvider { + + public ISymbolWriter GetSymbolWriter (ModuleDefinition module, string fileName) + { + return new MdbWriter (module.Mvid, fileName); + } + + public ISymbolWriter GetSymbolWriter (ModuleDefinition module, Stream symbolStream) + { + throw new NotImplementedException (); + } + } + + public class MdbWriter : ISymbolWriter { + + readonly Guid mvid; + readonly MonoSymbolWriter writer; + readonly Dictionary source_files; + + public MdbWriter (Guid mvid, string assembly) + { + this.mvid = mvid; + this.writer = new MonoSymbolWriter (assembly); + this.source_files = new Dictionary (); + } + + static Collection GetInstructions (MethodBody body) + { + var instructions = new Collection (); + foreach (var instruction in body.Instructions) + if (instruction.SequencePoint != null) + instructions.Add (instruction); + + return instructions; + } + + SourceFile GetSourceFile (Document document) + { + var url = document.Url; + + SourceFile source_file; + if (source_files.TryGetValue (url, out source_file)) + return source_file; + + var entry = writer.DefineDocument (url); + var compile_unit = writer.DefineCompilationUnit (entry); + + source_file = new SourceFile (compile_unit, entry); + source_files.Add (url, source_file); + return source_file; + } + + void Populate (Collection instructions, int [] offsets, + int [] startRows, int [] startCols, out SourceFile file) + { + SourceFile source_file = null; + + for (int i = 0; i < instructions.Count; i++) { + var instruction = instructions [i]; + offsets [i] = instruction.Offset; + + var sequence_point = instruction.SequencePoint; + if (source_file == null) + source_file = GetSourceFile (sequence_point.Document); + + startRows [i] = sequence_point.StartLine; + startCols [i] = sequence_point.StartColumn; + } + + file = source_file; + } + + public void Write (MethodBody body) + { + var method = new SourceMethod (body.Method); + + var instructions = GetInstructions (body); + int count = instructions.Count; + if (count == 0) + return; + + var offsets = new int [count]; + var start_rows = new int [count]; + var start_cols = new int [count]; + + SourceFile file; + Populate (instructions, offsets, start_rows, start_cols, out file); + + var builder = writer.OpenMethod (file.CompilationUnit, 0, method); + + for (int i = 0; i < count; i++) + builder.MarkSequencePoint ( + offsets [i], + file.CompilationUnit.SourceFile, + start_rows [i], + start_cols [i], + false); + + if (body.HasVariables) + AddVariables (body.Variables); + + writer.CloseMethod (); + } + + readonly static byte [] empty_header = new byte [0]; + + public bool GetDebugHeader (out ImageDebugDirectory directory, out byte [] header) + { + directory = new ImageDebugDirectory (); + header = empty_header; + return false; + } + + void AddVariables (IList variables) + { + for (int i = 0; i < variables.Count; i++) { + var variable = variables [i]; + writer.DefineLocalVariable (i, variable.Name); + } + } + + public void Write (MethodSymbols symbols) + { + var method = new SourceMethodSymbol (symbols); + + var file = GetSourceFile (symbols.Instructions [0].SequencePoint.Document); + var builder = writer.OpenMethod (file.CompilationUnit, 0, method); + var count = symbols.Instructions.Count; + + for (int i = 0; i < count; i++) { + var instruction = symbols.Instructions [i]; + var sequence_point = instruction.SequencePoint; + + builder.MarkSequencePoint ( + instruction.Offset, + GetSourceFile (sequence_point.Document).CompilationUnit.SourceFile, + sequence_point.StartLine, + sequence_point.EndLine, + false); + } + + if (symbols.HasVariables) + AddVariables (symbols.Variables); + + writer.CloseMethod (); + } + + public void Dispose () + { + writer.WriteSymbolFile (mvid); + } + + class SourceFile : ISourceFile { + + readonly CompileUnitEntry compilation_unit; + readonly SourceFileEntry entry; + + public SourceFileEntry Entry { + get { return entry; } + } + + public CompileUnitEntry CompilationUnit { + get { return compilation_unit; } + } + + public SourceFile (CompileUnitEntry comp_unit, SourceFileEntry entry) + { + this.compilation_unit = comp_unit; + this.entry = entry; + } + } + + class SourceMethodSymbol : IMethodDef { + + readonly string name; + readonly int token; + + public string Name { + get { return name;} + } + + public int Token { + get { return token; } + } + + public SourceMethodSymbol (MethodSymbols symbols) + { + name = symbols.MethodName; + token = symbols.MethodToken.ToInt32 (); + } + } + + class SourceMethod : IMethodDef { + + readonly MethodDefinition method; + + public string Name { + get { return method.Name; } + } + + public int Token { + get { return method.MetadataToken.ToInt32 (); } + } + + public SourceMethod (MethodDefinition method) + { + this.method = method; + } + } + } +#endif +} diff --git a/symbols/mdb/Mono.CompilerServices.SymbolWriter/MonoSymbolFile.cs b/symbols/mdb/Mono.CompilerServices.SymbolWriter/MonoSymbolFile.cs new file mode 100644 index 000000000..937b0a516 --- /dev/null +++ b/symbols/mdb/Mono.CompilerServices.SymbolWriter/MonoSymbolFile.cs @@ -0,0 +1,733 @@ +// +// Mono.CSharp.Debugger/MonoSymbolFile.cs +// +// Author: +// Martin Baulig (martin@ximian.com) +// +// (C) 2003 Ximian, Inc. http://www.ximian.com +// + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Reflection; +using SRE = System.Reflection.Emit; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using System.IO; + +namespace Mono.CompilerServices.SymbolWriter +{ + public class MonoSymbolFileException : Exception + { + public MonoSymbolFileException () + : base () + { } + + public MonoSymbolFileException (string message, params object[] args) + : base (String.Format (message, args)) + { } + } + + internal class MyBinaryWriter : BinaryWriter + { + public MyBinaryWriter (Stream stream) + : base (stream) + { } + + public void WriteLeb128 (int value) + { + base.Write7BitEncodedInt (value); + } + } + + internal class MyBinaryReader : BinaryReader + { + public MyBinaryReader (Stream stream) + : base (stream) + { } + + public int ReadLeb128 () + { + return base.Read7BitEncodedInt (); + } + + public string ReadString (int offset) + { + long old_pos = BaseStream.Position; + BaseStream.Position = offset; + + string text = ReadString (); + + BaseStream.Position = old_pos; + return text; + } + } + + public interface ISourceFile + { + SourceFileEntry Entry { + get; + } + } + + public interface ICompileUnit + { + CompileUnitEntry Entry { + get; + } + } + + public interface IMethodDef + { + string Name { + get; + } + + int Token { + get; + } + } + +#if !CECIL + internal class MonoDebuggerSupport + { + static GetMethodTokenFunc get_method_token; + static GetGuidFunc get_guid; + static GetLocalIndexFunc get_local_index; + + delegate int GetMethodTokenFunc (MethodBase method); + delegate Guid GetGuidFunc (Module module); + delegate int GetLocalIndexFunc (SRE.LocalBuilder local); + + static Delegate create_delegate (Type type, Type delegate_type, string name) + { + MethodInfo mi = type.GetMethod (name, BindingFlags.Static | + BindingFlags.NonPublic); + if (mi == null) + throw new Exception ("Can't find " + name); + + return Delegate.CreateDelegate (delegate_type, mi); + } + + static MonoDebuggerSupport () + { + get_method_token = (GetMethodTokenFunc) create_delegate ( + typeof (Assembly), typeof (GetMethodTokenFunc), + "MonoDebugger_GetMethodToken"); + + get_guid = (GetGuidFunc) create_delegate ( + typeof (Module), typeof (GetGuidFunc), "Mono_GetGuid"); + + get_local_index = (GetLocalIndexFunc) create_delegate ( + typeof (SRE.LocalBuilder), typeof (GetLocalIndexFunc), + "Mono_GetLocalIndex"); + } + + public static int GetMethodToken (MethodBase method) + { + return get_method_token (method); + } + + public static Guid GetGuid (Module module) + { + return get_guid (module); + } + + public static int GetLocalIndex (SRE.LocalBuilder local) + { + return get_local_index (local); + } + } +#endif + + public class MonoSymbolFile : IDisposable + { + List methods = new List (); + List sources = new List (); + List comp_units = new List (); + Dictionary type_hash = new Dictionary (); + Dictionary anonymous_scopes; + + OffsetTable ot; + int last_type_index; + int last_method_index; + int last_namespace_index; + + public readonly string FileName = ""; + public readonly int MajorVersion = OffsetTable.MajorVersion; + public readonly int MinorVersion = OffsetTable.MinorVersion; + + public int NumLineNumbers; + + internal MonoSymbolFile () + { + ot = new OffsetTable (); + } + + internal int AddSource (SourceFileEntry source) + { + sources.Add (source); + return sources.Count; + } + + internal int AddCompileUnit (CompileUnitEntry entry) + { + comp_units.Add (entry); + return comp_units.Count; + } + + internal int DefineType (Type type) + { + int index; + if (type_hash.TryGetValue (type, out index)) + return index; + + index = ++last_type_index; + type_hash.Add (type, index); + return index; + } + + internal void AddMethod (MethodEntry entry) + { + methods.Add (entry); + } + + public MethodEntry DefineMethod (CompileUnitEntry comp_unit, int token, + ScopeVariable[] scope_vars, LocalVariableEntry[] locals, + LineNumberEntry[] lines, CodeBlockEntry[] code_blocks, + string real_name, MethodEntry.Flags flags, + int namespace_id) + { + if (reader != null) + throw new InvalidOperationException (); + + MethodEntry method = new MethodEntry ( + this, comp_unit, token, scope_vars, locals, lines, code_blocks, + real_name, flags, namespace_id); + AddMethod (method); + return method; + } + + internal void DefineAnonymousScope (int id) + { + if (reader != null) + throw new InvalidOperationException (); + + if (anonymous_scopes == null) + anonymous_scopes = new Dictionary (); + + anonymous_scopes.Add (id, new AnonymousScopeEntry (id)); + } + + internal void DefineCapturedVariable (int scope_id, string name, string captured_name, + CapturedVariable.CapturedKind kind) + { + if (reader != null) + throw new InvalidOperationException (); + + AnonymousScopeEntry scope = anonymous_scopes [scope_id]; + scope.AddCapturedVariable (name, captured_name, kind); + } + + internal void DefineCapturedScope (int scope_id, int id, string captured_name) + { + if (reader != null) + throw new InvalidOperationException (); + + AnonymousScopeEntry scope = anonymous_scopes [scope_id]; + scope.AddCapturedScope (id, captured_name); + } + + internal int GetNextTypeIndex () + { + return ++last_type_index; + } + + internal int GetNextMethodIndex () + { + return ++last_method_index; + } + + internal int GetNextNamespaceIndex () + { + return ++last_namespace_index; + } + + void Write (MyBinaryWriter bw, Guid guid) + { + // Magic number and file version. + bw.Write (OffsetTable.Magic); + bw.Write (MajorVersion); + bw.Write (MinorVersion); + + bw.Write (guid.ToByteArray ()); + + // + // Offsets of file sections; we must write this after we're done + // writing the whole file, so we just reserve the space for it here. + // + long offset_table_offset = bw.BaseStream.Position; + ot.Write (bw, MajorVersion, MinorVersion); + + // + // Sort the methods according to their tokens and update their index. + // + methods.Sort (); + for (int i = 0; i < methods.Count; i++) + ((MethodEntry) methods [i]).Index = i + 1; + + // + // Write data sections. + // + ot.DataSectionOffset = (int) bw.BaseStream.Position; + foreach (SourceFileEntry source in sources) + source.WriteData (bw); + foreach (CompileUnitEntry comp_unit in comp_units) + comp_unit.WriteData (bw); + foreach (MethodEntry method in methods) + method.WriteData (this, bw); + ot.DataSectionSize = (int) bw.BaseStream.Position - ot.DataSectionOffset; + + // + // Write the method index table. + // + ot.MethodTableOffset = (int) bw.BaseStream.Position; + for (int i = 0; i < methods.Count; i++) { + MethodEntry entry = (MethodEntry) methods [i]; + entry.Write (bw); + } + ot.MethodTableSize = (int) bw.BaseStream.Position - ot.MethodTableOffset; + + // + // Write source table. + // + ot.SourceTableOffset = (int) bw.BaseStream.Position; + for (int i = 0; i < sources.Count; i++) { + SourceFileEntry source = (SourceFileEntry) sources [i]; + source.Write (bw); + } + ot.SourceTableSize = (int) bw.BaseStream.Position - ot.SourceTableOffset; + + // + // Write compilation unit table. + // + ot.CompileUnitTableOffset = (int) bw.BaseStream.Position; + for (int i = 0; i < comp_units.Count; i++) { + CompileUnitEntry unit = (CompileUnitEntry) comp_units [i]; + unit.Write (bw); + } + ot.CompileUnitTableSize = (int) bw.BaseStream.Position - ot.CompileUnitTableOffset; + + // + // Write anonymous scope table. + // + ot.AnonymousScopeCount = anonymous_scopes != null ? anonymous_scopes.Count : 0; + ot.AnonymousScopeTableOffset = (int) bw.BaseStream.Position; + if (anonymous_scopes != null) { + foreach (AnonymousScopeEntry scope in anonymous_scopes.Values) + scope.Write (bw); + } + ot.AnonymousScopeTableSize = (int) bw.BaseStream.Position - ot.AnonymousScopeTableOffset; + + // + // Fixup offset table. + // + ot.TypeCount = last_type_index; + ot.MethodCount = methods.Count; + ot.SourceCount = sources.Count; + ot.CompileUnitCount = comp_units.Count; + + // + // Write offset table. + // + ot.TotalFileSize = (int) bw.BaseStream.Position; + bw.Seek ((int) offset_table_offset, SeekOrigin.Begin); + ot.Write (bw, MajorVersion, MinorVersion); + bw.Seek (0, SeekOrigin.End); + +#if false + Console.WriteLine ("TOTAL: {0} line numbes, {1} bytes, extended {2} bytes, " + + "{3} methods.", NumLineNumbers, LineNumberSize, + ExtendedLineNumberSize, methods.Count); +#endif + } + + public void CreateSymbolFile (Guid guid, FileStream fs) + { + if (reader != null) + throw new InvalidOperationException (); + + Write (new MyBinaryWriter (fs), guid); + } + + MyBinaryReader reader; + Dictionary source_file_hash; + Dictionary compile_unit_hash; + + List method_list; + Dictionary method_token_hash; + Dictionary source_name_hash; + + Guid guid; + + MonoSymbolFile (string filename) + { + this.FileName = filename; + FileStream stream = new FileStream (filename, FileMode.Open, FileAccess.Read); + reader = new MyBinaryReader (stream); + + try { + long magic = reader.ReadInt64 (); + int major_version = reader.ReadInt32 (); + int minor_version = reader.ReadInt32 (); + + if (magic != OffsetTable.Magic) + throw new MonoSymbolFileException ( + "Symbol file `{0}' is not a valid " + + "Mono symbol file", filename); + if (major_version != OffsetTable.MajorVersion) + throw new MonoSymbolFileException ( + "Symbol file `{0}' has version {1}, " + + "but expected {2}", filename, major_version, + OffsetTable.MajorVersion); + if (minor_version != OffsetTable.MinorVersion) + throw new MonoSymbolFileException ( + "Symbol file `{0}' has version {1}.{2}, " + + "but expected {3}.{4}", filename, major_version, + minor_version, OffsetTable.MajorVersion, + OffsetTable.MinorVersion); + + MajorVersion = major_version; + MinorVersion = minor_version; + guid = new Guid (reader.ReadBytes (16)); + + ot = new OffsetTable (reader, major_version, minor_version); + } catch { + throw new MonoSymbolFileException ( + "Cannot read symbol file `{0}'", filename); + } + + source_file_hash = new Dictionary (); + compile_unit_hash = new Dictionary (); + } + + void CheckGuidMatch (Guid other, string filename, string assembly) + { + if (other == guid) + return; + + throw new MonoSymbolFileException ( + "Symbol file `{0}' does not match assembly `{1}'", + filename, assembly); + } + +#if CECIL + protected MonoSymbolFile (string filename, Mono.Cecil.ModuleDefinition module) + : this (filename) + { + CheckGuidMatch (module.Mvid, filename, module.FullyQualifiedName); + } + + public static MonoSymbolFile ReadSymbolFile (Mono.Cecil.ModuleDefinition module) + { + return ReadSymbolFile (module, module.FullyQualifiedName); + } + + public static MonoSymbolFile ReadSymbolFile (Mono.Cecil.ModuleDefinition module, string filename) + { + string name = filename + ".mdb"; + + return new MonoSymbolFile (name, module); + } +#else + protected MonoSymbolFile (string filename, Assembly assembly) : this (filename) + { + // Check that the MDB file matches the assembly, if we have been + // passed an assembly. + if (assembly == null) + return; + + Module[] modules = assembly.GetModules (); + Guid assembly_guid = MonoDebuggerSupport.GetGuid (modules [0]); + + CheckGuidMatch (assembly_guid, filename, assembly.Location); + } + + public static MonoSymbolFile ReadSymbolFile (Assembly assembly) + { + string filename = assembly.Location; + string name = filename + ".mdb"; + + return new MonoSymbolFile (name, assembly); + } +#endif + + public static MonoSymbolFile ReadSymbolFile (string mdbFilename) + { + return new MonoSymbolFile (mdbFilename, null); + } + + public int CompileUnitCount { + get { return ot.CompileUnitCount; } + } + + public int SourceCount { + get { return ot.SourceCount; } + } + + public int MethodCount { + get { return ot.MethodCount; } + } + + public int TypeCount { + get { return ot.TypeCount; } + } + + public int AnonymousScopeCount { + get { return ot.AnonymousScopeCount; } + } + + public int NamespaceCount { + get { return last_namespace_index; } + } + + public Guid Guid { + get { return guid; } + } + + public OffsetTable OffsetTable { + get { return ot; } + } + + internal int LineNumberCount = 0; + internal int LocalCount = 0; + internal int StringSize = 0; + + internal int LineNumberSize = 0; + internal int ExtendedLineNumberSize = 0; + + public SourceFileEntry GetSourceFile (int index) + { + if ((index < 1) || (index > ot.SourceCount)) + throw new ArgumentException (); + if (reader == null) + throw new InvalidOperationException (); + + lock (this) { + SourceFileEntry source; + if (source_file_hash.TryGetValue (index, out source)) + return source; + + long old_pos = reader.BaseStream.Position; + + reader.BaseStream.Position = ot.SourceTableOffset + + SourceFileEntry.Size * (index - 1); + source = new SourceFileEntry (this, reader); + source_file_hash.Add (index, source); + + reader.BaseStream.Position = old_pos; + return source; + } + } + + public SourceFileEntry[] Sources { + get { + if (reader == null) + throw new InvalidOperationException (); + + SourceFileEntry[] retval = new SourceFileEntry [SourceCount]; + for (int i = 0; i < SourceCount; i++) + retval [i] = GetSourceFile (i + 1); + return retval; + } + } + + public CompileUnitEntry GetCompileUnit (int index) + { + if ((index < 1) || (index > ot.CompileUnitCount)) + throw new ArgumentException (); + if (reader == null) + throw new InvalidOperationException (); + + lock (this) { + CompileUnitEntry unit; + if (compile_unit_hash.TryGetValue (index, out unit)) + return unit; + + long old_pos = reader.BaseStream.Position; + + reader.BaseStream.Position = ot.CompileUnitTableOffset + + CompileUnitEntry.Size * (index - 1); + unit = new CompileUnitEntry (this, reader); + compile_unit_hash.Add (index, unit); + + reader.BaseStream.Position = old_pos; + return unit; + } + } + + public CompileUnitEntry[] CompileUnits { + get { + if (reader == null) + throw new InvalidOperationException (); + + CompileUnitEntry[] retval = new CompileUnitEntry [CompileUnitCount]; + for (int i = 0; i < CompileUnitCount; i++) + retval [i] = GetCompileUnit (i + 1); + return retval; + } + } + + void read_methods () + { + lock (this) { + if (method_token_hash != null) + return; + + method_token_hash = new Dictionary (); + method_list = new List (); + + long old_pos = reader.BaseStream.Position; + reader.BaseStream.Position = ot.MethodTableOffset; + + for (int i = 0; i < MethodCount; i++) { + MethodEntry entry = new MethodEntry (this, reader, i + 1); + method_token_hash.Add (entry.Token, entry); + method_list.Add (entry); + } + + reader.BaseStream.Position = old_pos; + } + } + + public MethodEntry GetMethodByToken (int token) + { + if (reader == null) + throw new InvalidOperationException (); + + lock (this) { + read_methods (); + MethodEntry me; + method_token_hash.TryGetValue (token, out me); + return me; + } + } + + public MethodEntry GetMethod (int index) + { + if ((index < 1) || (index > ot.MethodCount)) + throw new ArgumentException (); + if (reader == null) + throw new InvalidOperationException (); + + lock (this) { + read_methods (); + return (MethodEntry) method_list [index - 1]; + } + } + + public MethodEntry[] Methods { + get { + if (reader == null) + throw new InvalidOperationException (); + + lock (this) { + read_methods (); + MethodEntry[] retval = new MethodEntry [MethodCount]; + method_list.CopyTo (retval, 0); + return retval; + } + } + } + + public int FindSource (string file_name) + { + if (reader == null) + throw new InvalidOperationException (); + + lock (this) { + if (source_name_hash == null) { + source_name_hash = new Dictionary (); + + for (int i = 0; i < ot.SourceCount; i++) { + SourceFileEntry source = GetSourceFile (i + 1); + source_name_hash.Add (source.FileName, i); + } + } + + int value; + if (!source_name_hash.TryGetValue (file_name, out value)) + return -1; + return value; + } + } + + public AnonymousScopeEntry GetAnonymousScope (int id) + { + if (reader == null) + throw new InvalidOperationException (); + + AnonymousScopeEntry scope; + lock (this) { + if (anonymous_scopes != null) { + anonymous_scopes.TryGetValue (id, out scope); + return scope; + } + + anonymous_scopes = new Dictionary (); + reader.BaseStream.Position = ot.AnonymousScopeTableOffset; + for (int i = 0; i < ot.AnonymousScopeCount; i++) { + scope = new AnonymousScopeEntry (reader); + anonymous_scopes.Add (scope.ID, scope); + } + + return anonymous_scopes [id]; + } + } + + internal MyBinaryReader BinaryReader { + get { + if (reader == null) + throw new InvalidOperationException (); + + return reader; + } + } + + public void Dispose () + { + Dispose (true); + } + + protected virtual void Dispose (bool disposing) + { + if (disposing) { + if (reader != null) { + reader.Close (); + reader = null; + } + } + } + } +} diff --git a/symbols/mdb/Mono.CompilerServices.SymbolWriter/MonoSymbolTable.cs b/symbols/mdb/Mono.CompilerServices.SymbolWriter/MonoSymbolTable.cs new file mode 100644 index 000000000..c170150ce --- /dev/null +++ b/symbols/mdb/Mono.CompilerServices.SymbolWriter/MonoSymbolTable.cs @@ -0,0 +1,1376 @@ +// +// Mono.CSharp.Debugger/MonoSymbolTable.cs +// +// Author: +// Martin Baulig (martin@ximian.com) +// +// (C) 2002 Ximian, Inc. http://www.ximian.com +// + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Security.Cryptography; +using System.Collections.Generic; +using System.Text; +using System.IO; + +// +// Parts which are actually written into the symbol file are marked with +// +// #region This is actually written to the symbol file +// #endregion +// +// Please do not modify these regions without previously talking to me. +// +// All changes to the file format must be synchronized in several places: +// +// a) The fields in these regions (and their order) must match the actual +// contents of the symbol file. +// +// This helps people to understand the symbol file format without reading +// too much source code, ie. you look at the appropriate region and then +// you know what's actually in the file. +// +// It is also required to help me enforce b). +// +// b) The regions must be kept in sync with the unmanaged code in +// mono/metadata/debug-mono-symfile.h +// +// When making changes to the file format, you must also increase two version +// numbers: +// +// i) OffsetTable.Version in this file. +// ii) MONO_SYMBOL_FILE_VERSION in mono/metadata/debug-mono-symfile.h +// +// After doing so, recompile everything, including the debugger. Symbol files +// with different versions are incompatible to each other and the debugger and +// the runtime enfore this, so you need to recompile all your assemblies after +// changing the file format. +// + +namespace Mono.CompilerServices.SymbolWriter +{ + public class OffsetTable + { + public const int MajorVersion = 50; + public const int MinorVersion = 0; + public const long Magic = 0x45e82623fd7fa614; + + #region This is actually written to the symbol file + public int TotalFileSize; + public int DataSectionOffset; + public int DataSectionSize; + public int CompileUnitCount; + public int CompileUnitTableOffset; + public int CompileUnitTableSize; + public int SourceCount; + public int SourceTableOffset; + public int SourceTableSize; + public int MethodCount; + public int MethodTableOffset; + public int MethodTableSize; + public int TypeCount; + public int AnonymousScopeCount; + public int AnonymousScopeTableOffset; + public int AnonymousScopeTableSize; + + [Flags] + public enum Flags + { + IsAspxSource = 1, + WindowsFileNames = 2 + } + + public Flags FileFlags; + + public int LineNumberTable_LineBase = LineNumberTable.Default_LineBase; + public int LineNumberTable_LineRange = LineNumberTable.Default_LineRange; + public int LineNumberTable_OpcodeBase = LineNumberTable.Default_OpcodeBase; + #endregion + + internal OffsetTable () + { + int platform = (int) Environment.OSVersion.Platform; + if ((platform != 4) && (platform != 128)) + FileFlags |= Flags.WindowsFileNames; + } + + internal OffsetTable (BinaryReader reader, int major_version, int minor_version) + { + TotalFileSize = reader.ReadInt32 (); + DataSectionOffset = reader.ReadInt32 (); + DataSectionSize = reader.ReadInt32 (); + CompileUnitCount = reader.ReadInt32 (); + CompileUnitTableOffset = reader.ReadInt32 (); + CompileUnitTableSize = reader.ReadInt32 (); + SourceCount = reader.ReadInt32 (); + SourceTableOffset = reader.ReadInt32 (); + SourceTableSize = reader.ReadInt32 (); + MethodCount = reader.ReadInt32 (); + MethodTableOffset = reader.ReadInt32 (); + MethodTableSize = reader.ReadInt32 (); + TypeCount = reader.ReadInt32 (); + + AnonymousScopeCount = reader.ReadInt32 (); + AnonymousScopeTableOffset = reader.ReadInt32 (); + AnonymousScopeTableSize = reader.ReadInt32 (); + + LineNumberTable_LineBase = reader.ReadInt32 (); + LineNumberTable_LineRange = reader.ReadInt32 (); + LineNumberTable_OpcodeBase = reader.ReadInt32 (); + + FileFlags = (Flags) reader.ReadInt32 (); + } + + internal void Write (BinaryWriter bw, int major_version, int minor_version) + { + bw.Write (TotalFileSize); + bw.Write (DataSectionOffset); + bw.Write (DataSectionSize); + bw.Write (CompileUnitCount); + bw.Write (CompileUnitTableOffset); + bw.Write (CompileUnitTableSize); + bw.Write (SourceCount); + bw.Write (SourceTableOffset); + bw.Write (SourceTableSize); + bw.Write (MethodCount); + bw.Write (MethodTableOffset); + bw.Write (MethodTableSize); + bw.Write (TypeCount); + + bw.Write (AnonymousScopeCount); + bw.Write (AnonymousScopeTableOffset); + bw.Write (AnonymousScopeTableSize); + + bw.Write (LineNumberTable_LineBase); + bw.Write (LineNumberTable_LineRange); + bw.Write (LineNumberTable_OpcodeBase); + + bw.Write ((int) FileFlags); + } + + public override string ToString () + { + return String.Format ( + "OffsetTable [{0} - {1}:{2} - {3}:{4}:{5} - {6}:{7}:{8} - {9}]", + TotalFileSize, DataSectionOffset, DataSectionSize, SourceCount, + SourceTableOffset, SourceTableSize, MethodCount, MethodTableOffset, + MethodTableSize, TypeCount); + } + } + + public class LineNumberEntry + { + #region This is actually written to the symbol file + public readonly int Row; + public readonly int File; + public readonly int Offset; + public readonly bool IsHidden; + #endregion + + public LineNumberEntry (int file, int row, int offset) + : this (file, row, offset, false) + { } + + public LineNumberEntry (int file, int row, int offset, bool is_hidden) + { + this.File = file; + this.Row = row; + this.Offset = offset; + this.IsHidden = is_hidden; + } + + public static LineNumberEntry Null = new LineNumberEntry (0, 0, 0); + + private class OffsetComparerClass : IComparer + { + public int Compare (LineNumberEntry l1, LineNumberEntry l2) + { + if (l1.Offset < l2.Offset) + return -1; + else if (l1.Offset > l2.Offset) + return 1; + else + return 0; + } + } + + private class RowComparerClass : IComparer + { + public int Compare (LineNumberEntry l1, LineNumberEntry l2) + { + if (l1.Row < l2.Row) + return -1; + else if (l1.Row > l2.Row) + return 1; + else + return 0; + } + } + + public static readonly IComparer OffsetComparer = new OffsetComparerClass (); + public static readonly IComparer RowComparer = new RowComparerClass (); + + public override string ToString () + { + return String.Format ("[Line {0}:{1}:{2}]", File, Row, Offset); + } + } + + public class CodeBlockEntry + { + public int Index; + #region This is actually written to the symbol file + public int Parent; + public Type BlockType; + public int StartOffset; + public int EndOffset; + #endregion + + public enum Type { + Lexical = 1, + CompilerGenerated = 2, + IteratorBody = 3, + IteratorDispatcher = 4 + } + + public CodeBlockEntry (int index, int parent, Type type, int start_offset) + { + this.Index = index; + this.Parent = parent; + this.BlockType = type; + this.StartOffset = start_offset; + } + + internal CodeBlockEntry (int index, MyBinaryReader reader) + { + this.Index = index; + int type_flag = reader.ReadLeb128 (); + BlockType = (Type) (type_flag & 0x3f); + this.Parent = reader.ReadLeb128 (); + this.StartOffset = reader.ReadLeb128 (); + this.EndOffset = reader.ReadLeb128 (); + + /* Reserved for future extensions. */ + if ((type_flag & 0x40) != 0) { + int data_size = reader.ReadInt16 (); + reader.BaseStream.Position += data_size; + } + } + + public void Close (int end_offset) + { + this.EndOffset = end_offset; + } + + internal void Write (MyBinaryWriter bw) + { + bw.WriteLeb128 ((int) BlockType); + bw.WriteLeb128 (Parent); + bw.WriteLeb128 (StartOffset); + bw.WriteLeb128 (EndOffset); + } + + public override string ToString () + { + return String.Format ("[CodeBlock {0}:{1}:{2}:{3}:{4}]", + Index, Parent, BlockType, StartOffset, EndOffset); + } + } + + public struct LocalVariableEntry + { + #region This is actually written to the symbol file + public readonly int Index; + public readonly string Name; + public readonly int BlockIndex; + #endregion + + public LocalVariableEntry (int index, string name, int block) + { + this.Index = index; + this.Name = name; + this.BlockIndex = block; + } + + internal LocalVariableEntry (MonoSymbolFile file, MyBinaryReader reader) + { + Index = reader.ReadLeb128 (); + Name = reader.ReadString (); + BlockIndex = reader.ReadLeb128 (); + } + + internal void Write (MonoSymbolFile file, MyBinaryWriter bw) + { + bw.WriteLeb128 (Index); + bw.Write (Name); + bw.WriteLeb128 (BlockIndex); + } + + public override string ToString () + { + return String.Format ("[LocalVariable {0}:{1}:{2}]", + Name, Index, BlockIndex - 1); + } + } + + public struct CapturedVariable + { + #region This is actually written to the symbol file + public readonly string Name; + public readonly string CapturedName; + public readonly CapturedKind Kind; + #endregion + + public enum CapturedKind : byte + { + Local, + Parameter, + This + } + + public CapturedVariable (string name, string captured_name, + CapturedKind kind) + { + this.Name = name; + this.CapturedName = captured_name; + this.Kind = kind; + } + + internal CapturedVariable (MyBinaryReader reader) + { + Name = reader.ReadString (); + CapturedName = reader.ReadString (); + Kind = (CapturedKind) reader.ReadByte (); + } + + internal void Write (MyBinaryWriter bw) + { + bw.Write (Name); + bw.Write (CapturedName); + bw.Write ((byte) Kind); + } + + public override string ToString () + { + return String.Format ("[CapturedVariable {0}:{1}:{2}]", + Name, CapturedName, Kind); + } + } + + public struct CapturedScope + { + #region This is actually written to the symbol file + public readonly int Scope; + public readonly string CapturedName; + #endregion + + public CapturedScope (int scope, string captured_name) + { + this.Scope = scope; + this.CapturedName = captured_name; + } + + internal CapturedScope (MyBinaryReader reader) + { + Scope = reader.ReadLeb128 (); + CapturedName = reader.ReadString (); + } + + internal void Write (MyBinaryWriter bw) + { + bw.WriteLeb128 (Scope); + bw.Write (CapturedName); + } + + public override string ToString () + { + return String.Format ("[CapturedScope {0}:{1}]", + Scope, CapturedName); + } + } + + public struct ScopeVariable + { + #region This is actually written to the symbol file + public readonly int Scope; + public readonly int Index; + #endregion + + public ScopeVariable (int scope, int index) + { + this.Scope = scope; + this.Index = index; + } + + internal ScopeVariable (MyBinaryReader reader) + { + Scope = reader.ReadLeb128 (); + Index = reader.ReadLeb128 (); + } + + internal void Write (MyBinaryWriter bw) + { + bw.WriteLeb128 (Scope); + bw.WriteLeb128 (Index); + } + + public override string ToString () + { + return String.Format ("[ScopeVariable {0}:{1}]", Scope, Index); + } + } + + public class AnonymousScopeEntry + { + #region This is actually written to the symbol file + public readonly int ID; + #endregion + + List captured_vars = new List (); + List captured_scopes = new List (); + + public AnonymousScopeEntry (int id) + { + this.ID = id; + } + + internal AnonymousScopeEntry (MyBinaryReader reader) + { + ID = reader.ReadLeb128 (); + + int num_captured_vars = reader.ReadLeb128 (); + for (int i = 0; i < num_captured_vars; i++) + captured_vars.Add (new CapturedVariable (reader)); + + int num_captured_scopes = reader.ReadLeb128 (); + for (int i = 0; i < num_captured_scopes; i++) + captured_scopes.Add (new CapturedScope (reader)); + } + + internal void AddCapturedVariable (string name, string captured_name, + CapturedVariable.CapturedKind kind) + { + captured_vars.Add (new CapturedVariable (name, captured_name, kind)); + } + + public CapturedVariable[] CapturedVariables { + get { + CapturedVariable[] retval = new CapturedVariable [captured_vars.Count]; + captured_vars.CopyTo (retval, 0); + return retval; + } + } + + internal void AddCapturedScope (int scope, string captured_name) + { + captured_scopes.Add (new CapturedScope (scope, captured_name)); + } + + public CapturedScope[] CapturedScopes { + get { + CapturedScope[] retval = new CapturedScope [captured_scopes.Count]; + captured_scopes.CopyTo (retval, 0); + return retval; + } + } + + internal void Write (MyBinaryWriter bw) + { + bw.WriteLeb128 (ID); + + bw.WriteLeb128 (captured_vars.Count); + foreach (CapturedVariable cv in captured_vars) + cv.Write (bw); + + bw.WriteLeb128 (captured_scopes.Count); + foreach (CapturedScope cs in captured_scopes) + cs.Write (bw); + } + + public override string ToString () + { + return String.Format ("[AnonymousScope {0}]", ID); + } + } + + public class CompileUnitEntry : ICompileUnit + { + #region This is actually written to the symbol file + public readonly int Index; + int DataOffset; + #endregion + + MonoSymbolFile file; + SourceFileEntry source; + List include_files; + List namespaces; + + bool creating; + + public static int Size { + get { return 8; } + } + + CompileUnitEntry ICompileUnit.Entry { + get { return this; } + } + + public CompileUnitEntry (MonoSymbolFile file, SourceFileEntry source) + { + this.file = file; + this.source = source; + + this.Index = file.AddCompileUnit (this); + + creating = true; + namespaces = new List (); + } + + public void AddFile (SourceFileEntry file) + { + if (!creating) + throw new InvalidOperationException (); + + if (include_files == null) + include_files = new List (); + + include_files.Add (file); + } + + public SourceFileEntry SourceFile { + get { + if (creating) + return source; + + ReadData (); + return source; + } + } + + public int DefineNamespace (string name, string[] using_clauses, int parent) + { + if (!creating) + throw new InvalidOperationException (); + + int index = file.GetNextNamespaceIndex (); + NamespaceEntry ns = new NamespaceEntry (name, index, using_clauses, parent); + namespaces.Add (ns); + return index; + } + + internal void WriteData (MyBinaryWriter bw) + { + DataOffset = (int) bw.BaseStream.Position; + bw.WriteLeb128 (source.Index); + + int count_includes = include_files != null ? include_files.Count : 0; + bw.WriteLeb128 (count_includes); + if (include_files != null) { + foreach (SourceFileEntry entry in include_files) + bw.WriteLeb128 (entry.Index); + } + + bw.WriteLeb128 (namespaces.Count); + foreach (NamespaceEntry ns in namespaces) + ns.Write (file, bw); + } + + internal void Write (BinaryWriter bw) + { + bw.Write (Index); + bw.Write (DataOffset); + } + + internal CompileUnitEntry (MonoSymbolFile file, MyBinaryReader reader) + { + this.file = file; + + Index = reader.ReadInt32 (); + DataOffset = reader.ReadInt32 (); + } + + void ReadData () + { + if (creating) + throw new InvalidOperationException (); + + lock (file) { + if (namespaces != null) + return; + + MyBinaryReader reader = file.BinaryReader; + int old_pos = (int) reader.BaseStream.Position; + + reader.BaseStream.Position = DataOffset; + + int source_idx = reader.ReadLeb128 (); + source = file.GetSourceFile (source_idx); + + int count_includes = reader.ReadLeb128 (); + if (count_includes > 0) { + include_files = new List (); + for (int i = 0; i < count_includes; i++) + include_files.Add (file.GetSourceFile (reader.ReadLeb128 ())); + } + + int count_ns = reader.ReadLeb128 (); + namespaces = new List (); + for (int i = 0; i < count_ns; i ++) + namespaces.Add (new NamespaceEntry (file, reader)); + + reader.BaseStream.Position = old_pos; + } + } + + public NamespaceEntry[] Namespaces { + get { + ReadData (); + NamespaceEntry[] retval = new NamespaceEntry [namespaces.Count]; + namespaces.CopyTo (retval, 0); + return retval; + } + } + + public SourceFileEntry[] IncludeFiles { + get { + ReadData (); + if (include_files == null) + return new SourceFileEntry [0]; + + SourceFileEntry[] retval = new SourceFileEntry [include_files.Count]; + include_files.CopyTo (retval, 0); + return retval; + } + } + } + + public class SourceFileEntry + { + #region This is actually written to the symbol file + public readonly int Index; + int DataOffset; + #endregion + + MonoSymbolFile file; + string file_name; + byte[] guid; + byte[] hash; + bool creating; + bool auto_generated; + + public static int Size { + get { return 8; } + } + + public SourceFileEntry (MonoSymbolFile file, string file_name) + { + this.file = file; + this.file_name = file_name; + this.Index = file.AddSource (this); + + creating = true; + } + + public SourceFileEntry (MonoSymbolFile file, string file_name, + byte[] guid, byte[] checksum) + : this (file, file_name) + { + this.guid = guid; + this.hash = checksum; + } + + internal void WriteData (MyBinaryWriter bw) + { + DataOffset = (int) bw.BaseStream.Position; + bw.Write (file_name); + + if (guid == null) { + guid = Guid.NewGuid ().ToByteArray (); + try { + using (FileStream fs = new FileStream (file_name, FileMode.Open, FileAccess.Read)) { + MD5 md5 = MD5.Create (); + hash = md5.ComputeHash (fs); + } + } catch { + hash = new byte [16]; + } + } + + bw.Write (guid); + bw.Write (hash); + bw.Write ((byte) (auto_generated ? 1 : 0)); + } + + internal void Write (BinaryWriter bw) + { + bw.Write (Index); + bw.Write (DataOffset); + } + + internal SourceFileEntry (MonoSymbolFile file, MyBinaryReader reader) + { + this.file = file; + + Index = reader.ReadInt32 (); + DataOffset = reader.ReadInt32 (); + + int old_pos = (int) reader.BaseStream.Position; + reader.BaseStream.Position = DataOffset; + + file_name = reader.ReadString (); + guid = reader.ReadBytes (16); + hash = reader.ReadBytes (16); + auto_generated = reader.ReadByte () == 1; + + reader.BaseStream.Position = old_pos; + } + + public string FileName { + get { return file_name; } + } + + public bool AutoGenerated { + get { return auto_generated; } + } + + public void SetAutoGenerated () + { + if (!creating) + throw new InvalidOperationException (); + + auto_generated = true; + file.OffsetTable.FileFlags |= OffsetTable.Flags.IsAspxSource; + } + + public bool CheckChecksum () + { + try { + using (FileStream fs = new FileStream (file_name, FileMode.Open)) { + MD5 md5 = MD5.Create (); + byte[] data = md5.ComputeHash (fs); + for (int i = 0; i < 16; i++) + if (data [i] != hash [i]) + return false; + return true; + } + } catch { + return false; + } + } + + public override string ToString () + { + return String.Format ("SourceFileEntry ({0}:{1})", Index, DataOffset); + } + } + + public class LineNumberTable + { + protected LineNumberEntry[] _line_numbers; + public LineNumberEntry[] LineNumbers { + get { return _line_numbers; } + } + + public readonly int LineBase; + public readonly int LineRange; + public readonly byte OpcodeBase; + public readonly int MaxAddressIncrement; + +#region Configurable constants + public const int Default_LineBase = -1; + public const int Default_LineRange = 8; + public const byte Default_OpcodeBase = 9; + + public const bool SuppressDuplicates = true; +#endregion + + public const byte DW_LNS_copy = 1; + public const byte DW_LNS_advance_pc = 2; + public const byte DW_LNS_advance_line = 3; + public const byte DW_LNS_set_file = 4; + public const byte DW_LNS_const_add_pc = 8; + + public const byte DW_LNE_end_sequence = 1; + + // MONO extensions. + public const byte DW_LNE_MONO_negate_is_hidden = 0x40; + + internal const byte DW_LNE_MONO__extensions_start = 0x40; + internal const byte DW_LNE_MONO__extensions_end = 0x7f; + + protected LineNumberTable (MonoSymbolFile file) + { + this.LineBase = file.OffsetTable.LineNumberTable_LineBase; + this.LineRange = file.OffsetTable.LineNumberTable_LineRange; + this.OpcodeBase = (byte) file.OffsetTable.LineNumberTable_OpcodeBase; + this.MaxAddressIncrement = (255 - OpcodeBase) / LineRange; + } + + internal LineNumberTable (MonoSymbolFile file, LineNumberEntry[] lines) + : this (file) + { + this._line_numbers = lines; + } + + internal void Write (MonoSymbolFile file, MyBinaryWriter bw) + { + int start = (int) bw.BaseStream.Position; + + bool last_is_hidden = false; + int last_line = 1, last_offset = 0, last_file = 1; + for (int i = 0; i < LineNumbers.Length; i++) { + int line_inc = LineNumbers [i].Row - last_line; + int offset_inc = LineNumbers [i].Offset - last_offset; + + if (SuppressDuplicates && (i+1 < LineNumbers.Length)) { + if (LineNumbers [i+1].Equals (LineNumbers [i])) + continue; + } + + if (LineNumbers [i].File != last_file) { + bw.Write (DW_LNS_set_file); + bw.WriteLeb128 (LineNumbers [i].File); + last_file = LineNumbers [i].File; + } + + if (LineNumbers [i].IsHidden != last_is_hidden) { + bw.Write ((byte) 0); + bw.Write ((byte) 1); + bw.Write (DW_LNE_MONO_negate_is_hidden); + last_is_hidden = LineNumbers [i].IsHidden; + } + + if (offset_inc >= MaxAddressIncrement) { + if (offset_inc < 2 * MaxAddressIncrement) { + bw.Write (DW_LNS_const_add_pc); + offset_inc -= MaxAddressIncrement; + } else { + bw.Write (DW_LNS_advance_pc); + bw.WriteLeb128 (offset_inc); + offset_inc = 0; + } + } + + if ((line_inc < LineBase) || (line_inc >= LineBase + LineRange)) { + bw.Write (DW_LNS_advance_line); + bw.WriteLeb128 (line_inc); + if (offset_inc != 0) { + bw.Write (DW_LNS_advance_pc); + bw.WriteLeb128 (offset_inc); + } + bw.Write (DW_LNS_copy); + } else { + byte opcode; + opcode = (byte) (line_inc - LineBase + (LineRange * offset_inc) + + OpcodeBase); + bw.Write (opcode); + } + + last_line = LineNumbers [i].Row; + last_offset = LineNumbers [i].Offset; + } + + bw.Write ((byte) 0); + bw.Write ((byte) 1); + bw.Write (DW_LNE_end_sequence); + + file.ExtendedLineNumberSize += (int) bw.BaseStream.Position - start; + } + + internal static LineNumberTable Read (MonoSymbolFile file, MyBinaryReader br) + { + LineNumberTable lnt = new LineNumberTable (file); + lnt.DoRead (file, br); + return lnt; + } + + void DoRead (MonoSymbolFile file, MyBinaryReader br) + { + var lines = new List (); + + bool is_hidden = false, modified = false; + int stm_line = 1, stm_offset = 0, stm_file = 1; + while (true) { + byte opcode = br.ReadByte (); + + if (opcode == 0) { + byte size = br.ReadByte (); + long end_pos = br.BaseStream.Position + size; + opcode = br.ReadByte (); + + if (opcode == DW_LNE_end_sequence) { + if (modified) + lines.Add (new LineNumberEntry ( + stm_file, stm_line, stm_offset, is_hidden)); + break; + } else if (opcode == DW_LNE_MONO_negate_is_hidden) { + is_hidden = !is_hidden; + modified = true; + } else if ((opcode >= DW_LNE_MONO__extensions_start) && + (opcode <= DW_LNE_MONO__extensions_end)) { + ; // reserved for future extensions + } else { + throw new MonoSymbolFileException ( + "Unknown extended opcode {0:x} in LNT ({1})", + opcode, file.FileName); + } + + br.BaseStream.Position = end_pos; + continue; + } else if (opcode < OpcodeBase) { + switch (opcode) { + case DW_LNS_copy: + lines.Add (new LineNumberEntry ( + stm_file, stm_line, stm_offset, is_hidden)); + modified = false; + break; + case DW_LNS_advance_pc: + stm_offset += br.ReadLeb128 (); + modified = true; + break; + case DW_LNS_advance_line: + stm_line += br.ReadLeb128 (); + modified = true; + break; + case DW_LNS_set_file: + stm_file = br.ReadLeb128 (); + modified = true; + break; + case DW_LNS_const_add_pc: + stm_offset += MaxAddressIncrement; + modified = true; + break; + default: + throw new MonoSymbolFileException ( + "Unknown standard opcode {0:x} in LNT", + opcode); + } + } else { + opcode -= OpcodeBase; + + stm_offset += opcode / LineRange; + stm_line += LineBase + (opcode % LineRange); + lines.Add (new LineNumberEntry ( + stm_file, stm_line, stm_offset, is_hidden)); + modified = false; + } + } + + _line_numbers = new LineNumberEntry [lines.Count]; + lines.CopyTo (_line_numbers, 0); + } + + public bool GetMethodBounds (out LineNumberEntry start, out LineNumberEntry end) + { + if (_line_numbers.Length > 1) { + start = _line_numbers [0]; + end = _line_numbers [_line_numbers.Length - 1]; + return true; + } + + start = LineNumberEntry.Null; + end = LineNumberEntry.Null; + return false; + } + } + + public class MethodEntry : IComparable + { + #region This is actually written to the symbol file + public readonly int CompileUnitIndex; + public readonly int Token; + public readonly int NamespaceID; + + int DataOffset; + int LocalVariableTableOffset; + int LineNumberTableOffset; + int CodeBlockTableOffset; + int ScopeVariableTableOffset; + int RealNameOffset; + Flags flags; + #endregion + + int index; + + public Flags MethodFlags { + get { return flags; } + } + + public readonly CompileUnitEntry CompileUnit; + + LocalVariableEntry[] locals; + CodeBlockEntry[] code_blocks; + ScopeVariable[] scope_vars; + LineNumberTable lnt; + string real_name; + + public readonly MonoSymbolFile SymbolFile; + + public int Index { + get { return index; } + set { index = value; } + } + + [Flags] + public enum Flags + { + LocalNamesAmbiguous = 1 + } + + public const int Size = 12; + + internal MethodEntry (MonoSymbolFile file, MyBinaryReader reader, int index) + { + this.SymbolFile = file; + this.index = index; + + Token = reader.ReadInt32 (); + DataOffset = reader.ReadInt32 (); + LineNumberTableOffset = reader.ReadInt32 (); + + long old_pos = reader.BaseStream.Position; + reader.BaseStream.Position = DataOffset; + + CompileUnitIndex = reader.ReadLeb128 (); + LocalVariableTableOffset = reader.ReadLeb128 (); + NamespaceID = reader.ReadLeb128 (); + + CodeBlockTableOffset = reader.ReadLeb128 (); + ScopeVariableTableOffset = reader.ReadLeb128 (); + + RealNameOffset = reader.ReadLeb128 (); + + flags = (Flags) reader.ReadLeb128 (); + + reader.BaseStream.Position = old_pos; + + CompileUnit = file.GetCompileUnit (CompileUnitIndex); + } + + internal MethodEntry (MonoSymbolFile file, CompileUnitEntry comp_unit, + int token, ScopeVariable[] scope_vars, + LocalVariableEntry[] locals, LineNumberEntry[] lines, + CodeBlockEntry[] code_blocks, string real_name, + Flags flags, int namespace_id) + { + this.SymbolFile = file; + this.real_name = real_name; + this.locals = locals; + this.code_blocks = code_blocks; + this.scope_vars = scope_vars; + this.flags = flags; + + index = -1; + + Token = token; + CompileUnitIndex = comp_unit.Index; + CompileUnit = comp_unit; + NamespaceID = namespace_id; + + CheckLineNumberTable (lines); + lnt = new LineNumberTable (file, lines); + file.NumLineNumbers += lines.Length; + + int num_locals = locals != null ? locals.Length : 0; + + if (num_locals <= 32) { + // Most of the time, the O(n^2) factor is actually + // less than the cost of allocating the hash table, + // 32 is a rough number obtained through some testing. + + for (int i = 0; i < num_locals; i ++) { + string nm = locals [i].Name; + + for (int j = i + 1; j < num_locals; j ++) { + if (locals [j].Name == nm) { + flags |= Flags.LocalNamesAmbiguous; + goto locals_check_done; + } + } + } + locals_check_done : + ; + } else { + var local_names = new Dictionary (); + foreach (LocalVariableEntry local in locals) { + if (local_names.ContainsKey (local.Name)) { + flags |= Flags.LocalNamesAmbiguous; + break; + } + local_names.Add (local.Name, local); + } + } + } + + void CheckLineNumberTable (LineNumberEntry[] line_numbers) + { + int last_offset = -1; + int last_row = -1; + + if (line_numbers == null) + return; + + for (int i = 0; i < line_numbers.Length; i++) { + LineNumberEntry line = line_numbers [i]; + + if (line.Equals (LineNumberEntry.Null)) + throw new MonoSymbolFileException (); + + if (line.Offset < last_offset) + throw new MonoSymbolFileException (); + + if (line.Offset > last_offset) { + last_row = line.Row; + last_offset = line.Offset; + } else if (line.Row > last_row) { + last_row = line.Row; + } + } + } + + internal void Write (MyBinaryWriter bw) + { + if ((index <= 0) || (DataOffset == 0)) + throw new InvalidOperationException (); + + bw.Write (Token); + bw.Write (DataOffset); + bw.Write (LineNumberTableOffset); + } + + internal void WriteData (MonoSymbolFile file, MyBinaryWriter bw) + { + if (index <= 0) + throw new InvalidOperationException (); + + LocalVariableTableOffset = (int) bw.BaseStream.Position; + int num_locals = locals != null ? locals.Length : 0; + bw.WriteLeb128 (num_locals); + for (int i = 0; i < num_locals; i++) + locals [i].Write (file, bw); + file.LocalCount += num_locals; + + CodeBlockTableOffset = (int) bw.BaseStream.Position; + int num_code_blocks = code_blocks != null ? code_blocks.Length : 0; + bw.WriteLeb128 (num_code_blocks); + for (int i = 0; i < num_code_blocks; i++) + code_blocks [i].Write (bw); + + ScopeVariableTableOffset = (int) bw.BaseStream.Position; + int num_scope_vars = scope_vars != null ? scope_vars.Length : 0; + bw.WriteLeb128 (num_scope_vars); + for (int i = 0; i < num_scope_vars; i++) + scope_vars [i].Write (bw); + + if (real_name != null) { + RealNameOffset = (int) bw.BaseStream.Position; + bw.Write (real_name); + } + + LineNumberTableOffset = (int) bw.BaseStream.Position; + lnt.Write (file, bw); + + DataOffset = (int) bw.BaseStream.Position; + + bw.WriteLeb128 (CompileUnitIndex); + bw.WriteLeb128 (LocalVariableTableOffset); + bw.WriteLeb128 (NamespaceID); + + bw.WriteLeb128 (CodeBlockTableOffset); + bw.WriteLeb128 (ScopeVariableTableOffset); + + bw.WriteLeb128 (RealNameOffset); + bw.WriteLeb128 ((int) flags); + } + + public LineNumberTable GetLineNumberTable () + { + lock (SymbolFile) { + if (lnt != null) + return lnt; + + if (LineNumberTableOffset == 0) + return null; + + MyBinaryReader reader = SymbolFile.BinaryReader; + long old_pos = reader.BaseStream.Position; + reader.BaseStream.Position = LineNumberTableOffset; + + lnt = LineNumberTable.Read (SymbolFile, reader); + + reader.BaseStream.Position = old_pos; + return lnt; + } + } + + public LocalVariableEntry[] GetLocals () + { + lock (SymbolFile) { + if (locals != null) + return locals; + + if (LocalVariableTableOffset == 0) + return null; + + MyBinaryReader reader = SymbolFile.BinaryReader; + long old_pos = reader.BaseStream.Position; + reader.BaseStream.Position = LocalVariableTableOffset; + + int num_locals = reader.ReadLeb128 (); + locals = new LocalVariableEntry [num_locals]; + + for (int i = 0; i < num_locals; i++) + locals [i] = new LocalVariableEntry (SymbolFile, reader); + + reader.BaseStream.Position = old_pos; + return locals; + } + } + + public CodeBlockEntry[] GetCodeBlocks () + { + lock (SymbolFile) { + if (code_blocks != null) + return code_blocks; + + if (CodeBlockTableOffset == 0) + return null; + + MyBinaryReader reader = SymbolFile.BinaryReader; + long old_pos = reader.BaseStream.Position; + reader.BaseStream.Position = CodeBlockTableOffset; + + int num_code_blocks = reader.ReadLeb128 (); + code_blocks = new CodeBlockEntry [num_code_blocks]; + + for (int i = 0; i < num_code_blocks; i++) + code_blocks [i] = new CodeBlockEntry (i, reader); + + reader.BaseStream.Position = old_pos; + return code_blocks; + } + } + + public ScopeVariable[] GetScopeVariables () + { + lock (SymbolFile) { + if (scope_vars != null) + return scope_vars; + + if (ScopeVariableTableOffset == 0) + return null; + + MyBinaryReader reader = SymbolFile.BinaryReader; + long old_pos = reader.BaseStream.Position; + reader.BaseStream.Position = ScopeVariableTableOffset; + + int num_scope_vars = reader.ReadLeb128 (); + scope_vars = new ScopeVariable [num_scope_vars]; + + for (int i = 0; i < num_scope_vars; i++) + scope_vars [i] = new ScopeVariable (reader); + + reader.BaseStream.Position = old_pos; + return scope_vars; + } + } + + public string GetRealName () + { + lock (SymbolFile) { + if (real_name != null) + return real_name; + + if (RealNameOffset == 0) + return null; + + real_name = SymbolFile.BinaryReader.ReadString (RealNameOffset); + return real_name; + } + } + + public int CompareTo (object obj) + { + MethodEntry method = (MethodEntry) obj; + + if (method.Token < Token) + return 1; + else if (method.Token > Token) + return -1; + else + return 0; + } + + public override string ToString () + { + return String.Format ("[Method {0}:{1:x}:{2}:{3}]", + index, Token, CompileUnitIndex, CompileUnit); + } + } + + public struct NamespaceEntry + { + #region This is actually written to the symbol file + public readonly string Name; + public readonly int Index; + public readonly int Parent; + public readonly string[] UsingClauses; + #endregion + + public NamespaceEntry (string name, int index, string[] using_clauses, int parent) + { + this.Name = name; + this.Index = index; + this.Parent = parent; + this.UsingClauses = using_clauses != null ? using_clauses : new string [0]; + } + + internal NamespaceEntry (MonoSymbolFile file, MyBinaryReader reader) + { + Name = reader.ReadString (); + Index = reader.ReadLeb128 (); + Parent = reader.ReadLeb128 (); + + int count = reader.ReadLeb128 (); + UsingClauses = new string [count]; + for (int i = 0; i < count; i++) + UsingClauses [i] = reader.ReadString (); + } + + internal void Write (MonoSymbolFile file, MyBinaryWriter bw) + { + bw.Write (Name); + bw.WriteLeb128 (Index); + bw.WriteLeb128 (Parent); + bw.WriteLeb128 (UsingClauses.Length); + foreach (string uc in UsingClauses) + bw.Write (uc); + } + + public override string ToString () + { + return String.Format ("[Namespace {0}:{1}:{2}]", Name, Index, Parent); + } + } +} diff --git a/symbols/mdb/Mono.CompilerServices.SymbolWriter/MonoSymbolWriter.cs b/symbols/mdb/Mono.CompilerServices.SymbolWriter/MonoSymbolWriter.cs new file mode 100644 index 000000000..db77c2527 --- /dev/null +++ b/symbols/mdb/Mono.CompilerServices.SymbolWriter/MonoSymbolWriter.cs @@ -0,0 +1,403 @@ +// +// Mono.CSharp.Debugger/MonoSymbolWriter.cs +// +// Author: +// Martin Baulig (martin@ximian.com) +// +// This is the default implementation of the System.Diagnostics.SymbolStore.ISymbolWriter +// interface. +// +// (C) 2002 Ximian, Inc. http://www.ximian.com +// + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Runtime.CompilerServices; +using System.Collections.Generic; +using System.IO; + +namespace Mono.CompilerServices.SymbolWriter +{ + public class MonoSymbolWriter + { + List methods; + List sources; + List comp_units; + protected readonly MonoSymbolFile file; + string filename; + + private SourceMethodBuilder current_method; +#if NET_2_1 + System.Collections.Stack current_method_stack = new System.Collections.Stack (); +#else + Stack current_method_stack = new Stack (); +#endif + + public MonoSymbolWriter (string filename) + { + this.methods = new List (); + this.sources = new List (); + this.comp_units = new List (); + this.file = new MonoSymbolFile (); + + this.filename = filename + ".mdb"; + } + + public MonoSymbolFile SymbolFile { + get { return file; } + } + + public void CloseNamespace () + { } + + public void DefineLocalVariable (int index, string name) + { + if (current_method == null) + return; + + current_method.AddLocal (index, name); + } + + public void DefineCapturedLocal (int scope_id, string name, string captured_name) + { + file.DefineCapturedVariable (scope_id, name, captured_name, + CapturedVariable.CapturedKind.Local); + } + + public void DefineCapturedParameter (int scope_id, string name, string captured_name) + { + file.DefineCapturedVariable (scope_id, name, captured_name, + CapturedVariable.CapturedKind.Parameter); + } + + public void DefineCapturedThis (int scope_id, string captured_name) + { + file.DefineCapturedVariable (scope_id, "this", captured_name, + CapturedVariable.CapturedKind.This); + } + + public void DefineCapturedScope (int scope_id, int id, string captured_name) + { + file.DefineCapturedScope (scope_id, id, captured_name); + } + + public void DefineScopeVariable (int scope, int index) + { + if (current_method == null) + return; + + current_method.AddScopeVariable (scope, index); + } + + public void MarkSequencePoint (int offset, SourceFileEntry file, int line, int column, + bool is_hidden) + { + if (current_method == null) + return; + + current_method.MarkSequencePoint (offset, file, line, column, is_hidden); + } + + public SourceMethodBuilder OpenMethod (ICompileUnit file, int ns_id, IMethodDef method) + { + SourceMethodBuilder builder = new SourceMethodBuilder (file, ns_id, method); + current_method_stack.Push (current_method); + current_method = builder; + methods.Add (current_method); + return builder; + } + + public void CloseMethod () + { + current_method = (SourceMethodBuilder) current_method_stack.Pop (); + } + + public SourceFileEntry DefineDocument (string url) + { + SourceFileEntry entry = new SourceFileEntry (file, url); + sources.Add (entry); + return entry; + } + + public SourceFileEntry DefineDocument (string url, byte[] guid, byte[] checksum) + { + SourceFileEntry entry = new SourceFileEntry (file, url, guid, checksum); + sources.Add (entry); + return entry; + } + + public CompileUnitEntry DefineCompilationUnit (SourceFileEntry source) + { + CompileUnitEntry entry = new CompileUnitEntry (file, source); + comp_units.Add (entry); + return entry; + } + + public int DefineNamespace (string name, CompileUnitEntry unit, + string[] using_clauses, int parent) + { + if ((unit == null) || (using_clauses == null)) + throw new NullReferenceException (); + + return unit.DefineNamespace (name, using_clauses, parent); + } + + public int OpenScope (int start_offset) + { + if (current_method == null) + return 0; + + current_method.StartBlock (CodeBlockEntry.Type.Lexical, start_offset); + return 0; + } + + public void CloseScope (int end_offset) + { + if (current_method == null) + return; + + current_method.EndBlock (end_offset); + } + + public void OpenCompilerGeneratedBlock (int start_offset) + { + if (current_method == null) + return; + + current_method.StartBlock (CodeBlockEntry.Type.CompilerGenerated, + start_offset); + } + + public void CloseCompilerGeneratedBlock (int end_offset) + { + if (current_method == null) + return; + + current_method.EndBlock (end_offset); + } + + public void StartIteratorBody (int start_offset) + { + current_method.StartBlock (CodeBlockEntry.Type.IteratorBody, + start_offset); + } + + public void EndIteratorBody (int end_offset) + { + current_method.EndBlock (end_offset); + } + + public void StartIteratorDispatcher (int start_offset) + { + current_method.StartBlock (CodeBlockEntry.Type.IteratorDispatcher, + start_offset); + } + + public void EndIteratorDispatcher (int end_offset) + { + current_method.EndBlock (end_offset); + } + + public void DefineAnonymousScope (int id) + { + file.DefineAnonymousScope (id); + } + + public void WriteSymbolFile (Guid guid) + { + foreach (SourceMethodBuilder method in methods) + method.DefineMethod (file); + + try { + // We mmap the file, so unlink the previous version since it may be in use + File.Delete (filename); + } catch { + // We can safely ignore + } + using (FileStream fs = new FileStream (filename, FileMode.Create, FileAccess.Write)) { + file.CreateSymbolFile (guid, fs); + } + } + } + + public class SourceMethodBuilder + { + List _locals; + List _blocks; + List _scope_vars; +#if NET_2_1 + System.Collections.Stack _block_stack; +#else + Stack _block_stack; +#endif + string _real_name; + IMethodDef _method; + ICompileUnit _comp_unit; +// MethodEntry.Flags _method_flags; + int _ns_id; + + public SourceMethodBuilder (ICompileUnit comp_unit, int ns_id, IMethodDef method) + { + this._comp_unit = comp_unit; + this._method = method; + this._ns_id = ns_id; + + method_lines = new LineNumberEntry [32]; + } + + private LineNumberEntry [] method_lines; + private int method_lines_pos = 0; + + public void MarkSequencePoint (int offset, SourceFileEntry file, int line, int column, + bool is_hidden) + { + if (method_lines_pos == method_lines.Length) { + LineNumberEntry [] tmp = method_lines; + method_lines = new LineNumberEntry [method_lines.Length * 2]; + Array.Copy (tmp, method_lines, method_lines_pos); + } + + int file_idx = file != null ? file.Index : 0; + method_lines [method_lines_pos++] = new LineNumberEntry ( + file_idx, line, offset, is_hidden); + } + + public void StartBlock (CodeBlockEntry.Type type, int start_offset) + { + if (_block_stack == null) { +#if NET_2_1 + _block_stack = new System.Collections.Stack (); +#else + _block_stack = new Stack (); +#endif + } + + if (_blocks == null) + _blocks = new List (); + + int parent = CurrentBlock != null ? CurrentBlock.Index : -1; + + CodeBlockEntry block = new CodeBlockEntry ( + _blocks.Count + 1, parent, type, start_offset); + + _block_stack.Push (block); + _blocks.Add (block); + } + + public void EndBlock (int end_offset) + { + CodeBlockEntry block = (CodeBlockEntry) _block_stack.Pop (); + block.Close (end_offset); + } + + public CodeBlockEntry[] Blocks { + get { + if (_blocks == null) + return new CodeBlockEntry [0]; + + CodeBlockEntry[] retval = new CodeBlockEntry [_blocks.Count]; + _blocks.CopyTo (retval, 0); + return retval; + } + } + + public CodeBlockEntry CurrentBlock { + get { + if ((_block_stack != null) && (_block_stack.Count > 0)) + return (CodeBlockEntry) _block_stack.Peek (); + else + return null; + } + } + + public LocalVariableEntry[] Locals { + get { + if (_locals == null) + return new LocalVariableEntry [0]; + else { + LocalVariableEntry[] retval = + new LocalVariableEntry [_locals.Count]; + _locals.CopyTo (retval, 0); + return retval; + } + } + } + + public void AddLocal (int index, string name) + { + if (_locals == null) + _locals = new List (); + int block_idx = CurrentBlock != null ? CurrentBlock.Index : 0; + _locals.Add (new LocalVariableEntry (index, name, block_idx)); + } + + public ScopeVariable[] ScopeVariables { + get { + if (_scope_vars == null) + return new ScopeVariable [0]; + + ScopeVariable[] retval = new ScopeVariable [_scope_vars.Count]; + _scope_vars.CopyTo (retval); + return retval; + } + } + + public void AddScopeVariable (int scope, int index) + { + if (_scope_vars == null) + _scope_vars = new List (); + _scope_vars.Add ( + new ScopeVariable (scope, index)); + } + + public string RealMethodName { + get { return _real_name; } + } + + public void SetRealMethodName (string name) + { + _real_name = name; + } + + public ICompileUnit SourceFile { + get { return _comp_unit; } + } + + public IMethodDef Method { + get { return _method; } + } + + public void DefineMethod (MonoSymbolFile file) + { + LineNumberEntry[] lines = new LineNumberEntry [method_lines_pos]; + Array.Copy (method_lines, lines, method_lines_pos); + + MethodEntry entry = new MethodEntry ( + file, _comp_unit.Entry, _method.Token, ScopeVariables, + Locals, lines, Blocks, RealMethodName, 0, //_method_flags, + _ns_id); + + file.AddMethod (entry); + } + } +} diff --git a/symbols/mdb/Mono.CompilerServices.SymbolWriter/SymbolWriterImpl.cs b/symbols/mdb/Mono.CompilerServices.SymbolWriter/SymbolWriterImpl.cs new file mode 100644 index 000000000..d9e30578e --- /dev/null +++ b/symbols/mdb/Mono.CompilerServices.SymbolWriter/SymbolWriterImpl.cs @@ -0,0 +1,349 @@ +// +// SymbolWriterImpl.cs +// +// Author: +// Lluis Sanchez Gual (lluis@novell.com) +// +// (C) 2005 Novell, Inc. http://www.novell.com +// +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + + +using System; +using System.Reflection; +using System.Reflection.Emit; +using System.Runtime.CompilerServices; +using System.Collections; +using System.IO; +using System.Diagnostics.SymbolStore; + +namespace Mono.CompilerServices.SymbolWriter +{ + public class SymbolWriterImpl: ISymbolWriter + { + MonoSymbolWriter msw; + + int nextLocalIndex; + int currentToken; + string methodName; + Stack namespaceStack = new Stack (); + bool methodOpened; + + Hashtable documents = new Hashtable (); + +#if !CECIL + ModuleBuilder mb; + delegate Guid GetGuidFunc (ModuleBuilder mb); + GetGuidFunc get_guid_func; + + public SymbolWriterImpl (ModuleBuilder mb) + { + this.mb = mb; + } + + public void Close () + { + MethodInfo mi = typeof (ModuleBuilder).GetMethod ( + "Mono_GetGuid", + BindingFlags.Static | BindingFlags.NonPublic); + if (mi == null) + return; + + get_guid_func = (GetGuidFunc) System.Delegate.CreateDelegate ( + typeof (GetGuidFunc), mi); + + msw.WriteSymbolFile (get_guid_func (mb)); + } +#else + Guid guid; + + public SymbolWriterImpl (Guid guid) + { + this.guid = guid; + } + + public void Close () + { + msw.WriteSymbolFile (guid); + } +#endif + + public void CloseMethod () + { + if (methodOpened) { + methodOpened = false; + nextLocalIndex = 0; + msw.CloseMethod (); + } + } + + public void CloseNamespace () + { + namespaceStack.Pop (); + msw.CloseNamespace (); + } + + public void CloseScope (int endOffset) + { + msw.CloseScope (endOffset); + } + + public ISymbolDocumentWriter DefineDocument ( + string url, + Guid language, + Guid languageVendor, + Guid documentType) + { + SymbolDocumentWriterImpl doc = (SymbolDocumentWriterImpl) documents [url]; + if (doc == null) { + SourceFileEntry entry = msw.DefineDocument (url); + CompileUnitEntry comp_unit = msw.DefineCompilationUnit (entry); + doc = new SymbolDocumentWriterImpl (comp_unit); + documents [url] = doc; + } + return doc; + } + + public void DefineField ( + SymbolToken parent, + string name, + FieldAttributes attributes, + byte[] signature, + SymAddressKind addrKind, + int addr1, + int addr2, + int addr3) + { + } + + public void DefineGlobalVariable ( + string name, + FieldAttributes attributes, + byte[] signature, + SymAddressKind addrKind, + int addr1, + int addr2, + int addr3) + { + } + + public void DefineLocalVariable ( + string name, + FieldAttributes attributes, + byte[] signature, + SymAddressKind addrKind, + int addr1, + int addr2, + int addr3, + int startOffset, + int endOffset) + { + msw.DefineLocalVariable (nextLocalIndex++, name); + } + + public void DefineParameter ( + string name, + ParameterAttributes attributes, + int sequence, + SymAddressKind addrKind, + int addr1, + int addr2, + int addr3) + { + } + + public void DefineSequencePoints ( + ISymbolDocumentWriter document, + int[] offsets, + int[] lines, + int[] columns, + int[] endLines, + int[] endColumns) + { + SymbolDocumentWriterImpl doc = (SymbolDocumentWriterImpl) document; + SourceFileEntry file = doc != null ? doc.Entry.SourceFile : null; + + for (int n=0; n 0 && offsets[n] == offsets[n-1] && lines[n] == lines[n-1] && columns[n] == columns[n-1]) + continue; + msw.MarkSequencePoint (offsets[n], file, lines[n], columns[n], false); + } + } + + public void Initialize (IntPtr emitter, string filename, bool fFullBuild) + { + msw = new MonoSymbolWriter (filename); + } + + public void OpenMethod (SymbolToken method) + { + currentToken = method.GetToken (); + } + + public void OpenNamespace (string name) + { + NamespaceInfo n = new NamespaceInfo (); + n.NamespaceID = -1; + n.Name = name; + namespaceStack.Push (n); + } + + public int OpenScope (int startOffset) + { + return msw.OpenScope (startOffset); + } + + public void SetMethodSourceRange ( + ISymbolDocumentWriter startDoc, + int startLine, + int startColumn, + ISymbolDocumentWriter endDoc, + int endLine, + int endColumn) + { + int nsId = GetCurrentNamespace (startDoc); + SourceMethodImpl sm = new SourceMethodImpl (methodName, currentToken, nsId); + msw.OpenMethod (((ICompileUnit)startDoc).Entry, nsId, sm); + methodOpened = true; + } + + public void SetScopeRange (int scopeID, int startOffset, int endOffset) + { + } + + public void SetSymAttribute (SymbolToken parent, string name, byte[] data) + { + // This is a hack! but MonoSymbolWriter needs the method name + // and ISymbolWriter does not have any method for providing it + if (name == "__name") + methodName = System.Text.Encoding.UTF8.GetString (data); + } + + public void SetUnderlyingWriter (IntPtr underlyingWriter) + { + } + + public void SetUserEntryPoint (SymbolToken entryMethod) + { + } + + public void UsingNamespace (string fullName) + { + if (namespaceStack.Count == 0) { + OpenNamespace (""); + } + + NamespaceInfo ni = (NamespaceInfo) namespaceStack.Peek (); + if (ni.NamespaceID != -1) { + NamespaceInfo old = ni; + CloseNamespace (); + OpenNamespace (old.Name); + ni = (NamespaceInfo) namespaceStack.Peek (); + ni.UsingClauses = old.UsingClauses; + } + ni.UsingClauses.Add (fullName); + } + + int GetCurrentNamespace (ISymbolDocumentWriter doc) + { + if (namespaceStack.Count == 0) { + OpenNamespace (""); + } + + NamespaceInfo ni = (NamespaceInfo) namespaceStack.Peek (); + if (ni.NamespaceID == -1) + { + string[] usings = (string[]) ni.UsingClauses.ToArray (typeof(string)); + + int parentId = 0; + if (namespaceStack.Count > 1) { + namespaceStack.Pop (); + parentId = ((NamespaceInfo) namespaceStack.Peek ()).NamespaceID; + namespaceStack.Push (ni); + } + + ni.NamespaceID = msw.DefineNamespace (ni.Name, ((ICompileUnit)doc).Entry, usings, parentId); + } + return ni.NamespaceID; + } + + } + + class SymbolDocumentWriterImpl: ISymbolDocumentWriter, ISourceFile, ICompileUnit + { + CompileUnitEntry comp_unit; + + public SymbolDocumentWriterImpl (CompileUnitEntry comp_unit) + { + this.comp_unit = comp_unit; + } + + public void SetCheckSum (Guid algorithmId, byte[] checkSum) + { + } + + public void SetSource (byte[] source) + { + } + + SourceFileEntry ISourceFile.Entry { + get { return comp_unit.SourceFile; } + } + + public CompileUnitEntry Entry { + get { return comp_unit; } + } + } + + class SourceMethodImpl: IMethodDef + { + string name; + int token; + int namespaceID; + + public SourceMethodImpl (string name, int token, int namespaceID) + { + this.name = name; + this.token = token; + this.namespaceID = namespaceID; + } + + public string Name { + get { return name; } + } + + public int NamespaceID { + get { return namespaceID; } + } + + public int Token { + get { return token; } + } + } + + class NamespaceInfo + { + public string Name; + public int NamespaceID; + public ArrayList UsingClauses = new ArrayList (); + } +} diff --git a/symbols/mdb/Test/.gitignore b/symbols/mdb/Test/.gitignore new file mode 100644 index 000000000..17ff3483d --- /dev/null +++ b/symbols/mdb/Test/.gitignore @@ -0,0 +1,4 @@ +bin +obj +*.xml +*.user diff --git a/symbols/mdb/Test/Mono.Cecil.Mdb.Tests.csproj b/symbols/mdb/Test/Mono.Cecil.Mdb.Tests.csproj new file mode 100644 index 000000000..ef5b01f95 --- /dev/null +++ b/symbols/mdb/Test/Mono.Cecil.Mdb.Tests.csproj @@ -0,0 +1,119 @@ + + + + net_4_0_Debug + AnyCPU + 9.0.30729 + 2.0 + {AC71DF9C-99FA-4A63-990A-66C8010355A6} + Library + Properties + Mono.Cecil.Mdb.Tests + Mono.Cecil.Mdb.Tests + 512 + + + true + full + false + bin\net_2_0_Debug\ + DEBUG;TRACE + prompt + 4 + v2.0 + + + pdbonly + true + bin\net_2_0_Release\ + TRACE + prompt + 4 + v2.0 + + + true + full + false + bin\net_3_5_Debug\ + DEBUG;TRACE;NET_3_5 + prompt + 4 + v3.5 + + + pdbonly + true + bin\net_3_5_Release\ + TRACE;NET_3_5 + prompt + 4 + v3.5 + + + true + full + false + bin\net_4_0_Debug\ + DEBUG;TRACE;NET_3_5;NET_4_0 + prompt + 4 + v4.0 + + + pdbonly + true + bin\net_4_0_Release\ + TRACE;NET_3_5;NET_4_0 + prompt + 4 + v4.0 + + + + + + + {D68133BD-1E63-496E-9EDE-4FBDBF77B486} + Mono.Cecil + + + {A47B1F49-A81A-43E8-BE6B-DD28AF2C4055} + Mono.Cecil.Tests + + + {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD} + Mono.Cecil.Mdb + + + + + + + + + + + + + False + ..\..\..\Test\libs\nunit-2.4.8\nunit.core.dll + + + False + ..\..\..\Test\libs\nunit-2.4.8\nunit.core.interfaces.dll + + + False + ..\..\..\Test\libs\nunit-2.4.8\nunit.framework.dll + + + + + \ No newline at end of file diff --git a/symbols/mdb/Test/Mono.Cecil.Tests/Addin.cs b/symbols/mdb/Test/Mono.Cecil.Tests/Addin.cs new file mode 100644 index 000000000..4865122b0 --- /dev/null +++ b/symbols/mdb/Test/Mono.Cecil.Tests/Addin.cs @@ -0,0 +1,8 @@ +using NUnit.Core.Extensibility; + +namespace Mono.Cecil.Tests { + + [NUnitAddin] + public class CecilMdbAddin : CecilTestAddin { + } +} diff --git a/symbols/mdb/Test/Mono.Cecil.Tests/MdbTests.cs b/symbols/mdb/Test/Mono.Cecil.Tests/MdbTests.cs new file mode 100644 index 000000000..757732d6e --- /dev/null +++ b/symbols/mdb/Test/Mono.Cecil.Tests/MdbTests.cs @@ -0,0 +1,58 @@ + +using Mono.Cecil.Mdb; + +using NUnit.Framework; + +namespace Mono.Cecil.Tests { + + [TestFixture] + public class MdbTests : BaseTestFixture { + + [TestModule ("hello.exe", SymbolReaderProvider = typeof (MdbReaderProvider), SymbolWriterProvider = typeof (MdbWriterProvider))] + public void Main (ModuleDefinition module) + { + var type = module.GetType ("Program"); + var main = type.GetMethod ("Main"); + + AssertCode (@" + .locals init (System.Int32 i) + .line 7,7:0,0 'C:\sources\cecil\symbols\Mono.Cecil.Mdb\Test\Resources\assemblies\hello.cs' + IL_0000: ldc.i4.0 + IL_0001: stloc.0 + .line 7,7:0,0 'C:\sources\cecil\symbols\Mono.Cecil.Mdb\Test\Resources\assemblies\hello.cs' + IL_0002: br IL_0013 + .line 8,8:0,0 'C:\sources\cecil\symbols\Mono.Cecil.Mdb\Test\Resources\assemblies\hello.cs' + IL_0007: ldarg.0 + IL_0008: ldloc.0 + IL_0009: ldelem.ref + IL_000a: call System.Void Program::Print(System.String) + .line 7,7:0,0 'C:\sources\cecil\symbols\Mono.Cecil.Mdb\Test\Resources\assemblies\hello.cs' + IL_000f: ldloc.0 + IL_0010: ldc.i4.1 + IL_0011: add + IL_0012: stloc.0 + IL_0013: ldloc.0 + IL_0014: ldarg.0 + IL_0015: ldlen + IL_0016: conv.i4 + IL_0017: blt IL_0007 + .line 10,10:0,0 'C:\sources\cecil\symbols\Mono.Cecil.Mdb\Test\Resources\assemblies\hello.cs' + IL_001c: ldc.i4.0 + IL_001d: ret +", main); + } + + static void AssertCode (string expected, MethodDefinition method) + { + Assert.IsTrue (method.HasBody); + Assert.IsNotNull (method.Body); + + Assert.AreEqual (Normalize (expected), Normalize (Formatter.FormatMethodBody (method))); + } + + static string Normalize (string str) + { + return str.Trim ().Replace ("\r\n", "\n"); + } + } +} diff --git a/symbols/mdb/Test/Resources/assemblies/hello.exe b/symbols/mdb/Test/Resources/assemblies/hello.exe new file mode 100644 index 0000000000000000000000000000000000000000..c2e4b9b38aae004609a24330f16a59a3313dbcc5 GIT binary patch literal 3072 zcmeHI&u<$=6#mw6Oln#yQAL`nZP+LQMOC%3N+2Lr#3V6oAit>7G%85V+8*qM^{%yE zmjnqE2?@akQK?)wgXob15)~3B4xB3SC-hFMUUJ5KZ+17?ga~m!;y|A>Gw;{D`QCf8 zlcgJ9q7Oipqt^rOaTO}*`R}J4nhVeVRKO3%?vLFw7VnR(HJy&x4*W)7x6GRDd46bC zl^JwB)A7vtm5SN&>&iNDB0mv_UM&NQMjuwre)VQ@+5;4fr;S_$N`MKO@hEW>bS9Tf z|*fDsc|5xxXGjQ5GSN1MR$J>j1-gC;PLa<5aql9H`Z zZH1IS6Ogp&1P+}~^`;ecf*Q>lTPgNqY0^|8dMi+_Pe+Y)lU9k9=SWcrm`#bA?L9YW zQolzfGh%PVt4Pb_C7+||=A0jtx73pDcxZKMexQ_9cU>frqP#QcM{x|;ATEP}xa2NS zPTG5P?0;7~nwjL$`ST}>S&T9?g`wg6%TlsT?(0c*B9}Y0k&4>q#c8qkqs@7jWBg;F&I7&?z7htG*XWSN0HaCH7eDHplBQgd8)M zS>Y3U0x#(~%4iS^l=|s!;GrpoPe(?yw5z4tcnc>fn`2_Tjki(I*UZ2=Wdk-5ivJLv zr{%QfEu6tQ^4T4_9H1g4L7$ME8xE8B&H1gi9XeIVb;9k} zLN=<}4OM)i6+2nt<+v)SsNj}UQ@WGH+GoNT`0>Mc)=y78_&f{4C@_hEbA`UAjDb<9 z;#y|-dSJJgeXqP#Q|-|4y|rfGf6y_`eDurosb3$JzwNKTa`%Pr?k1`Kx2vJA*GTk= zrl3UkgB{yRDal41lXq>S1l&or^G;@p+I3WLlXDqY$u01uU8cOi`Ss}4#n0KtenSyv+;n@Gg99pU_{}8m%_99olV#^z$i2^nG@h&<$b= z>E%%0I3m(-+NX%*H-##BV2UrhfmQDGQAZawMp-9@fM+GA6k*Xf8NdX07?|UZ7T*ZL zwaqHnlvIo<@i`dxu+Jo`VPKKF8r<#bh;7D_EE;GM31DiBdHP9JLXFJR-uuy-)Vlon z#Hg^v0bJ0rlZwt$*I{lFxy>j^W>NgJjGp8pImkK5XHnGkN#Y!?3{rKG`p6q7SXbg4 xq#Kf1vR|aAN=IWB9Q*Z%x?U%u7WV~se-9N8dP0A#fEoQC%Sa=h(EqLie*$+u1I_>d literal 0 HcmV?d00001 diff --git a/symbols/mdb/Test/Resources/assemblies/hello.exe.mdb b/symbols/mdb/Test/Resources/assemblies/hello.exe.mdb new file mode 100644 index 0000000000000000000000000000000000000000..f57f16561880fe11072c65c55af974adafa34d0a GIT binary patch literal 369 zcmWexR{vL7?S-om0|ZFd9yS+0{?>IVYl`IxwT~_~z&3 z>p6pj^n6p2VnR}jOJagjVQLeLi&Jxxax#J1GE#GL^7WF7RTtMRTe$DB%ao15PP32p zOm`CKzoNeG`?u5|6L@{6{Jj8lFBq}~R~DC~<}xrcfgHonz{X(1z{tq>ijna(;}@Va zfr>JLe2AnB13x#Hl(8pQsWeDYGZSM6(?pQN85o#(8M&=Nf-9I9S2C>v3Ia8={RGN< f1!5qVO%5m^1jN7qVKWBO+CU6M-~a^CcYqiG=b~8% literal 0 HcmV?d00001 diff --git a/symbols/pdb/.gitignore b/symbols/pdb/.gitignore new file mode 100644 index 000000000..17ff3483d --- /dev/null +++ b/symbols/pdb/.gitignore @@ -0,0 +1,4 @@ +bin +obj +*.xml +*.user diff --git a/symbols/pdb/Microsoft.Cci.Pdb/BitAccess.cs b/symbols/pdb/Microsoft.Cci.Pdb/BitAccess.cs new file mode 100644 index 000000000..852f79793 --- /dev/null +++ b/symbols/pdb/Microsoft.Cci.Pdb/BitAccess.cs @@ -0,0 +1,229 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.IO; +using System.Text; + +namespace Microsoft.Cci.Pdb { + internal class BitAccess { + + internal BitAccess(int capacity) { + this.buffer = new byte[capacity]; + this.offset = 0; + } + + internal byte[] Buffer { + get { return buffer; } + } + private byte[] buffer; + + internal void FillBuffer(Stream stream, int capacity) { + MinCapacity(capacity); + stream.Read(buffer, 0, capacity); + offset = 0; + } + + internal int Position { + get { return offset; } + set { offset = value; } + } + private int offset; + + internal void WriteBuffer(Stream stream, int count) { + stream.Write(buffer, 0, count); + } + + internal void MinCapacity(int capacity) { + if (buffer.Length < capacity) { + buffer = new byte[capacity]; + } + offset = 0; + } + + internal void Align(int alignment) { + while ((offset % alignment) != 0) { + offset++; + } + } + + internal void WriteInt32(int value) { + buffer[offset + 0] = (byte)value; + buffer[offset + 1] = (byte)(value >> 8); + buffer[offset + 2] = (byte)(value >> 16); + buffer[offset + 3] = (byte)(value >> 24); + offset += 4; + } + + internal void WriteInt32(int[] values) { + for (int i = 0; i < values.Length; i++) { + WriteInt32(values[i]); + } + } + + internal void WriteBytes(byte[] bytes) { + for (int i = 0; i < bytes.Length; i++) { + buffer[offset++] = bytes[i]; + } + } + + internal void ReadInt16(out short value) { + value = (short)((buffer[offset + 0] & 0xFF) | + (buffer[offset + 1] << 8)); + offset += 2; + } + + internal void ReadInt32(out int value) { + value = (int)((buffer[offset + 0] & 0xFF) | + (buffer[offset + 1] << 8) | + (buffer[offset + 2] << 16) | + (buffer[offset + 3] << 24)); + offset += 4; + } + + internal void ReadInt64(out long value) { + value = (long)((buffer[offset + 0] & 0xFF) | + (buffer[offset + 1] << 8) | + (buffer[offset + 2] << 16) | + (buffer[offset + 3] << 24) | + (buffer[offset + 4] << 32) | + (buffer[offset + 5] << 40) | + (buffer[offset + 6] << 48) | + (buffer[offset + 7] << 56)); + offset += 8; + } + + internal void ReadUInt16(out ushort value) { + value = (ushort)((buffer[offset + 0] & 0xFF) | + (buffer[offset + 1] << 8)); + offset += 2; + } + + internal void ReadUInt8(out byte value) { + value = (byte)((buffer[offset + 0] & 0xFF)); + offset += 1; + } + + internal void ReadUInt32(out uint value) { + value = (uint)((buffer[offset + 0] & 0xFF) | + (buffer[offset + 1] << 8) | + (buffer[offset + 2] << 16) | + (buffer[offset + 3] << 24)); + offset += 4; + } + + internal void ReadUInt64(out ulong value) { + value = (ulong)((buffer[offset + 0] & 0xFF) | + (buffer[offset + 1] << 8) | + (buffer[offset + 2] << 16) | + (buffer[offset + 3] << 24) | + (buffer[offset + 4] << 32) | + (buffer[offset + 5] << 40) | + (buffer[offset + 6] << 48) | + (buffer[offset + 7] << 56)); + offset += 8; + } + + internal void ReadInt32(int[] values) { + for (int i = 0; i < values.Length; i++) { + ReadInt32(out values[i]); + } + } + + internal void ReadUInt32(uint[] values) { + for (int i = 0; i < values.Length; i++) { + ReadUInt32(out values[i]); + } + } + + internal void ReadBytes(byte[] bytes) { + for (int i = 0; i < bytes.Length; i++) { + bytes[i] = buffer[offset++]; + } + } + + internal float ReadFloat() { + float result = BitConverter.ToSingle(buffer, offset); + offset += 4; + return result; + } + + internal double ReadDouble() { + double result = BitConverter.ToDouble(buffer, offset); + offset += 8; + return result; + } + + internal decimal ReadDecimal() { + int[] bits = new int[4]; + this.ReadInt32(bits); + return new decimal(bits); + } + + internal void ReadBString(out string value) { + ushort len; + this.ReadUInt16(out len); + value = Encoding.UTF8.GetString(buffer, offset, len); + offset += len; + } + + internal void ReadCString(out string value) { + int len = 0; + while (offset + len < buffer.Length && buffer[offset + len] != 0) { + len++; + } + value = Encoding.UTF8.GetString(buffer, offset, len); + offset += len + 1; + } + + internal void SkipCString(out string value) { + int len = 0; + while (offset + len < buffer.Length && buffer[offset + len] != 0) { + len++; + } + offset += len + 1; + value= null; + } + + internal void ReadGuid(out Guid guid) { + uint a; + ushort b; + ushort c; + byte d; + byte e; + byte f; + byte g; + byte h; + byte i; + byte j; + byte k; + + ReadUInt32(out a); + ReadUInt16(out b); + ReadUInt16(out c); + ReadUInt8(out d); + ReadUInt8(out e); + ReadUInt8(out f); + ReadUInt8(out g); + ReadUInt8(out h); + ReadUInt8(out i); + ReadUInt8(out j); + ReadUInt8(out k); + + guid = new Guid(a, b, c, d, e, f, g, h, i, j, k); + } + + internal string ReadString() { + int len = 0; + while (offset + len < buffer.Length && buffer[offset + len] != 0) { + len+=2; + } + string result = Encoding.Unicode.GetString(buffer, offset, len); + offset += len + 2; + return result; + } + + } +} diff --git a/symbols/pdb/Microsoft.Cci.Pdb/BitSet.cs b/symbols/pdb/Microsoft.Cci.Pdb/BitSet.cs new file mode 100644 index 000000000..a9ed7f76e --- /dev/null +++ b/symbols/pdb/Microsoft.Cci.Pdb/BitSet.cs @@ -0,0 +1,69 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; + +namespace Microsoft.Cci.Pdb { + internal struct BitSet { + internal BitSet(BitAccess bits) { + bits.ReadInt32(out size); // 0..3 : Number of words + words = new uint[size]; + bits.ReadUInt32(words); + } + + internal BitSet(int size) { + this.size = size; + words = new uint[size]; + } + + internal bool IsSet(int index) { + int word = index / 32; + if (word >= this.size) return false; + return ((words[word] & GetBit(index)) != 0); + } + + internal void Set(int index) { + int word = index / 32; + if (word >= this.size) return; + words[word] |= GetBit(index); + } + + internal void Clear(int index) { + int word = index / 32; + if (word >= this.size) return; + words[word] &= ~GetBit(index); + } + + private uint GetBit(int index) { + return ((uint)1 << (index % 32)); + } + + private uint ReverseBits(uint value) { + uint o = 0; + for (int i = 0; i < 32; i++) { + o = (o << 1) | (value & 1); + value >>= 1; + } + return o; + } + + internal bool IsEmpty { + get { return size == 0; } + } + + internal bool GetWord(int index, out uint word) { + if (index < size) { + word = ReverseBits(words[index]); + return true; + } + word = 0; + return false; + } + + private int size; + private uint[] words; + } + +} diff --git a/symbols/pdb/Microsoft.Cci.Pdb/CvInfo.cs b/symbols/pdb/Microsoft.Cci.Pdb/CvInfo.cs new file mode 100644 index 000000000..bef308653 --- /dev/null +++ b/symbols/pdb/Microsoft.Cci.Pdb/CvInfo.cs @@ -0,0 +1,2430 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +// +// File: CvInfo.cs +// +// Generic CodeView information definitions +// +// Structures, constants, etc. for accessing and interpreting +// CodeView information. +// +// The master copy of this file resides in the langapi project (in C++). +// All Microsoft projects are required to use the master copy without +// modification. Modification of the master version or a copy +// without consultation with all parties concerned is extremely +// risky. +// +// When this file is modified, the corresponding documentation file +// omfdeb.doc in the langapi project must be updated. +// +// This is a read-only copy of the C++ file converted to C#. +// +using System; + +namespace Microsoft.Cci.Pdb { + internal struct FLOAT10 { + internal byte Data_0; + internal byte Data_1; + internal byte Data_2; + internal byte Data_3; + internal byte Data_4; + internal byte Data_5; + internal byte Data_6; + internal byte Data_7; + internal byte Data_8; + internal byte Data_9; + }; + + internal enum CV_SIGNATURE { + C6=0, // Actual signature is >64K + C7=1, // First explicit signature + C11=2, // C11 (vc5.x) 32-bit types + C13=4, // C13 (vc7.x) zero terminated names + RESERVERD=5, // All signatures from 5 to 64K are reserved + }; + + // CodeView Symbol and Type OMF type information is broken up into two + // ranges. Type indices less than 0x1000 describe type information + // that is frequently used. Type indices above 0x1000 are used to + // describe more complex features such as functions, arrays and + // structures. + // + + // Primitive types have predefined meaning that is encoded in the + // values of the various bit fields in the value. + // + // A CodeView primitive type is defined as: + // + // 1 1 + // 1 089 7654 3 210 + // r mode type r sub + // + // Where + // mode is the pointer mode + // type is a type indicator + // sub is a subtype enumeration + // r is a reserved field + // + // See Microsoft Symbol and Type OMF (Version 4.0) for more + // information. + // + + // pointer mode enumeration values + + internal enum CV_prmode { + CV_TM_DIRECT=0, // mode is not a pointer + CV_TM_NPTR32=4, // mode is a 32 bit near pointer + CV_TM_NPTR64=6, // mode is a 64 bit near pointer + CV_TM_NPTR128=7, // mode is a 128 bit near pointer + }; + + // type enumeration values + + internal enum CV_type { + CV_SPECIAL=0x00, // special type size values + CV_SIGNED=0x01, // signed integral size values + CV_UNSIGNED=0x02, // unsigned integral size values + CV_BOOLEAN=0x03, // Boolean size values + CV_REAL=0x04, // real number size values + CV_COMPLEX=0x05, // complex number size values + CV_SPECIAL2=0x06, // second set of special types + CV_INT=0x07, // integral (int) values + CV_CVRESERVED=0x0f, + }; + + // subtype enumeration values for CV_SPECIAL + + internal enum CV_special { + CV_SP_NOTYPE=0x00, + CV_SP_ABS=0x01, + CV_SP_SEGMENT=0x02, + CV_SP_VOID=0x03, + CV_SP_CURRENCY=0x04, + CV_SP_NBASICSTR=0x05, + CV_SP_FBASICSTR=0x06, + CV_SP_NOTTRANS=0x07, + CV_SP_HRESULT=0x08, + }; + + // subtype enumeration values for CV_SPECIAL2 + + internal enum CV_special2 { + CV_S2_BIT=0x00, + CV_S2_PASCHAR=0x01, // Pascal CHAR + }; + + // subtype enumeration values for CV_SIGNED, CV_UNSIGNED and CV_BOOLEAN + + internal enum CV_integral { + CV_IN_1BYTE=0x00, + CV_IN_2BYTE=0x01, + CV_IN_4BYTE=0x02, + CV_IN_8BYTE=0x03, + CV_IN_16BYTE=0x04, + }; + + // subtype enumeration values for CV_REAL and CV_COMPLEX + + internal enum CV_real { + CV_RC_REAL32=0x00, + CV_RC_REAL64=0x01, + CV_RC_REAL80=0x02, + CV_RC_REAL128=0x03, + }; + + // subtype enumeration values for CV_INT (really int) + + internal enum CV_int { + CV_RI_CHAR=0x00, + CV_RI_INT1=0x00, + CV_RI_WCHAR=0x01, + CV_RI_UINT1=0x01, + CV_RI_INT2=0x02, + CV_RI_UINT2=0x03, + CV_RI_INT4=0x04, + CV_RI_UINT4=0x05, + CV_RI_INT8=0x06, + CV_RI_UINT8=0x07, + CV_RI_INT16=0x08, + CV_RI_UINT16=0x09, + }; + + internal struct CV_PRIMITIVE_TYPE { + const uint CV_MMASK = 0x700; // mode mask + const uint CV_TMASK = 0x0f0; // type mask + const uint CV_SMASK = 0x00f; // subtype mask + + const int CV_MSHIFT = 8; // primitive mode right shift count + const int CV_TSHIFT = 4; // primitive type right shift count + const int CV_SSHIFT = 0; // primitive subtype right shift count + + // function to extract primitive mode, type and size + + internal static CV_prmode CV_MODE(TYPE_ENUM typ) { + return (CV_prmode)((((uint)typ) & CV_MMASK) >> CV_MSHIFT); + } + + internal static CV_type CV_TYPE(TYPE_ENUM typ) { + return (CV_type)((((uint)typ) & CV_TMASK) >> CV_TSHIFT); + } + + internal static uint CV_SUBT(TYPE_ENUM typ) { + return ((((uint)typ) & CV_SMASK) >> CV_SSHIFT); + } + + // functions to check the type of a primitive + + internal static bool CV_TYP_IS_DIRECT(TYPE_ENUM typ) { + return (CV_MODE(typ) == CV_prmode.CV_TM_DIRECT); + } + + internal static bool CV_TYP_IS_PTR(TYPE_ENUM typ) { + return (CV_MODE(typ) != CV_prmode.CV_TM_DIRECT); + } + + internal static bool CV_TYP_IS_SIGNED(TYPE_ENUM typ) { + return + (((CV_TYPE(typ) == CV_type.CV_SIGNED) && CV_TYP_IS_DIRECT(typ)) || + (typ == TYPE_ENUM.T_INT1) || + (typ == TYPE_ENUM.T_INT2) || + (typ == TYPE_ENUM.T_INT4) || + (typ == TYPE_ENUM.T_INT8) || + (typ == TYPE_ENUM.T_INT16) || + (typ == TYPE_ENUM.T_RCHAR)); + } + + internal static bool CV_TYP_IS_UNSIGNED(TYPE_ENUM typ) { + return (((CV_TYPE(typ) == CV_type.CV_UNSIGNED) && CV_TYP_IS_DIRECT(typ)) || + (typ == TYPE_ENUM.T_UINT1) || + (typ == TYPE_ENUM.T_UINT2) || + (typ == TYPE_ENUM.T_UINT4) || + (typ == TYPE_ENUM.T_UINT8) || + (typ == TYPE_ENUM.T_UINT16)); + } + + internal static bool CV_TYP_IS_REAL(TYPE_ENUM typ) { + return ((CV_TYPE(typ) == CV_type.CV_REAL) && CV_TYP_IS_DIRECT(typ)); + } + + const uint CV_FIRST_NONPRIM = 0x1000; + + internal static bool CV_IS_PRIMITIVE(TYPE_ENUM typ) { + return ((uint)(typ) < CV_FIRST_NONPRIM); + } + + internal static bool CV_TYP_IS_COMPLEX(TYPE_ENUM typ) { + return ((CV_TYPE(typ) == CV_type.CV_COMPLEX) && CV_TYP_IS_DIRECT(typ)); + } + + internal static bool CV_IS_INTERNAL_PTR(TYPE_ENUM typ) { + return (CV_IS_PRIMITIVE(typ) && + CV_TYPE(typ) == CV_type.CV_CVRESERVED && + CV_TYP_IS_PTR(typ)); + } + } + + // selected values for type_index - for a more complete definition, see + // Microsoft Symbol and Type OMF document + + // Special Types + + internal enum TYPE_ENUM { + // Special Types + + T_NOTYPE=0x0000, // uncharacterized type (no type) + T_ABS=0x0001, // absolute symbol + T_SEGMENT=0x0002, // segment type + T_VOID=0x0003, // void + T_HRESULT=0x0008, // OLE/COM HRESULT + T_32PHRESULT=0x0408, // OLE/COM HRESULT __ptr32// + T_64PHRESULT=0x0608, // OLE/COM HRESULT __ptr64// + T_PVOID=0x0103, // near pointer to void + T_PFVOID=0x0203, // far pointer to void + T_PHVOID=0x0303, // huge pointer to void + T_32PVOID=0x0403, // 32 bit pointer to void + T_64PVOID=0x0603, // 64 bit pointer to void + T_CURRENCY=0x0004, // BASIC 8 byte currency value + T_NOTTRANS=0x0007, // type not translated by cvpack + T_BIT=0x0060, // bit + T_PASCHAR=0x0061, // Pascal CHAR + + // Character types + + T_CHAR=0x0010, // 8 bit signed + T_32PCHAR=0x0410, // 32 bit pointer to 8 bit signed + T_64PCHAR=0x0610, // 64 bit pointer to 8 bit signed + + T_UCHAR=0x0020, // 8 bit unsigned + T_32PUCHAR=0x0420, // 32 bit pointer to 8 bit unsigned + T_64PUCHAR=0x0620, // 64 bit pointer to 8 bit unsigned + + // really a character types + + T_RCHAR=0x0070, // really a char + T_32PRCHAR=0x0470, // 32 bit pointer to a real char + T_64PRCHAR=0x0670, // 64 bit pointer to a real char + + // really a wide character types + + T_WCHAR=0x0071, // wide char + T_32PWCHAR=0x0471, // 32 bit pointer to a wide char + T_64PWCHAR=0x0671, // 64 bit pointer to a wide char + + // 8 bit int types + + T_INT1=0x0068, // 8 bit signed int + T_32PINT1=0x0468, // 32 bit pointer to 8 bit signed int + T_64PINT1=0x0668, // 64 bit pointer to 8 bit signed int + + T_UINT1=0x0069, // 8 bit unsigned int + T_32PUINT1=0x0469, // 32 bit pointer to 8 bit unsigned int + T_64PUINT1=0x0669, // 64 bit pointer to 8 bit unsigned int + + // 16 bit short types + + T_SHORT=0x0011, // 16 bit signed + T_32PSHORT=0x0411, // 32 bit pointer to 16 bit signed + T_64PSHORT=0x0611, // 64 bit pointer to 16 bit signed + + T_USHORT=0x0021, // 16 bit unsigned + T_32PUSHORT=0x0421, // 32 bit pointer to 16 bit unsigned + T_64PUSHORT=0x0621, // 64 bit pointer to 16 bit unsigned + + // 16 bit int types + + T_INT2=0x0072, // 16 bit signed int + T_32PINT2=0x0472, // 32 bit pointer to 16 bit signed int + T_64PINT2=0x0672, // 64 bit pointer to 16 bit signed int + + T_UINT2=0x0073, // 16 bit unsigned int + T_32PUINT2=0x0473, // 32 bit pointer to 16 bit unsigned int + T_64PUINT2=0x0673, // 64 bit pointer to 16 bit unsigned int + + // 32 bit long types + + T_LONG=0x0012, // 32 bit signed + T_ULONG=0x0022, // 32 bit unsigned + T_32PLONG=0x0412, // 32 bit pointer to 32 bit signed + T_32PULONG=0x0422, // 32 bit pointer to 32 bit unsigned + T_64PLONG=0x0612, // 64 bit pointer to 32 bit signed + T_64PULONG=0x0622, // 64 bit pointer to 32 bit unsigned + + // 32 bit int types + + T_INT4=0x0074, // 32 bit signed int + T_32PINT4=0x0474, // 32 bit pointer to 32 bit signed int + T_64PINT4=0x0674, // 64 bit pointer to 32 bit signed int + + T_UINT4=0x0075, // 32 bit unsigned int + T_32PUINT4=0x0475, // 32 bit pointer to 32 bit unsigned int + T_64PUINT4=0x0675, // 64 bit pointer to 32 bit unsigned int + + // 64 bit quad types + + T_QUAD=0x0013, // 64 bit signed + T_32PQUAD=0x0413, // 32 bit pointer to 64 bit signed + T_64PQUAD=0x0613, // 64 bit pointer to 64 bit signed + + T_UQUAD=0x0023, // 64 bit unsigned + T_32PUQUAD=0x0423, // 32 bit pointer to 64 bit unsigned + T_64PUQUAD=0x0623, // 64 bit pointer to 64 bit unsigned + + // 64 bit int types + + T_INT8=0x0076, // 64 bit signed int + T_32PINT8=0x0476, // 32 bit pointer to 64 bit signed int + T_64PINT8=0x0676, // 64 bit pointer to 64 bit signed int + + T_UINT8=0x0077, // 64 bit unsigned int + T_32PUINT8=0x0477, // 32 bit pointer to 64 bit unsigned int + T_64PUINT8=0x0677, // 64 bit pointer to 64 bit unsigned int + + // 128 bit octet types + + T_OCT=0x0014, // 128 bit signed + T_32POCT=0x0414, // 32 bit pointer to 128 bit signed + T_64POCT=0x0614, // 64 bit pointer to 128 bit signed + + T_UOCT=0x0024, // 128 bit unsigned + T_32PUOCT=0x0424, // 32 bit pointer to 128 bit unsigned + T_64PUOCT=0x0624, // 64 bit pointer to 128 bit unsigned + + // 128 bit int types + + T_INT16=0x0078, // 128 bit signed int + T_32PINT16=0x0478, // 32 bit pointer to 128 bit signed int + T_64PINT16=0x0678, // 64 bit pointer to 128 bit signed int + + T_UINT16=0x0079, // 128 bit unsigned int + T_32PUINT16=0x0479, // 32 bit pointer to 128 bit unsigned int + T_64PUINT16=0x0679, // 64 bit pointer to 128 bit unsigned int + + // 32 bit real types + + T_REAL32=0x0040, // 32 bit real + T_32PREAL32=0x0440, // 32 bit pointer to 32 bit real + T_64PREAL32=0x0640, // 64 bit pointer to 32 bit real + + // 64 bit real types + + T_REAL64=0x0041, // 64 bit real + T_32PREAL64=0x0441, // 32 bit pointer to 64 bit real + T_64PREAL64=0x0641, // 64 bit pointer to 64 bit real + + // 80 bit real types + + T_REAL80=0x0042, // 80 bit real + T_32PREAL80=0x0442, // 32 bit pointer to 80 bit real + T_64PREAL80=0x0642, // 64 bit pointer to 80 bit real + + // 128 bit real types + + T_REAL128=0x0043, // 128 bit real + T_32PREAL128=0x0443, // 32 bit pointer to 128 bit real + T_64PREAL128=0x0643, // 64 bit pointer to 128 bit real + + // 32 bit complex types + + T_CPLX32=0x0050, // 32 bit complex + T_32PCPLX32=0x0450, // 32 bit pointer to 32 bit complex + T_64PCPLX32=0x0650, // 64 bit pointer to 32 bit complex + + // 64 bit complex types + + T_CPLX64=0x0051, // 64 bit complex + T_32PCPLX64=0x0451, // 32 bit pointer to 64 bit complex + T_64PCPLX64=0x0651, // 64 bit pointer to 64 bit complex + + // 80 bit complex types + + T_CPLX80=0x0052, // 80 bit complex + T_32PCPLX80=0x0452, // 32 bit pointer to 80 bit complex + T_64PCPLX80=0x0652, // 64 bit pointer to 80 bit complex + + // 128 bit complex types + + T_CPLX128=0x0053, // 128 bit complex + T_32PCPLX128=0x0453, // 32 bit pointer to 128 bit complex + T_64PCPLX128=0x0653, // 64 bit pointer to 128 bit complex + + // boolean types + + T_BOOL08=0x0030, // 8 bit boolean + T_32PBOOL08=0x0430, // 32 bit pointer to 8 bit boolean + T_64PBOOL08=0x0630, // 64 bit pointer to 8 bit boolean + + T_BOOL16=0x0031, // 16 bit boolean + T_32PBOOL16=0x0431, // 32 bit pointer to 18 bit boolean + T_64PBOOL16=0x0631, // 64 bit pointer to 18 bit boolean + + T_BOOL32=0x0032, // 32 bit boolean + T_32PBOOL32=0x0432, // 32 bit pointer to 32 bit boolean + T_64PBOOL32=0x0632, // 64 bit pointer to 32 bit boolean + + T_BOOL64=0x0033, // 64 bit boolean + T_32PBOOL64=0x0433, // 32 bit pointer to 64 bit boolean + T_64PBOOL64=0x0633, // 64 bit pointer to 64 bit boolean + }; + + // No leaf index can have a value of 0x0000. The leaf indices are + // separated into ranges depending upon the use of the type record. + // The second range is for the type records that are directly referenced + // in symbols. The first range is for type records that are not + // referenced by symbols but instead are referenced by other type + // records. All type records must have a starting leaf index in these + // first two ranges. The third range of leaf indices are used to build + // up complex lists such as the field list of a class type record. No + // type record can begin with one of the leaf indices. The fourth ranges + // of type indices are used to represent numeric data in a symbol or + // type record. These leaf indices are greater than 0x8000. At the + // point that type or symbol processor is expecting a numeric field, the + // next two bytes in the type record are examined. If the value is less + // than 0x8000, then the two bytes contain the numeric value. If the + // value is greater than 0x8000, then the data follows the leaf index in + // a format specified by the leaf index. The final range of leaf indices + // are used to force alignment of subfields within a complex type record.. + // + + internal enum LEAF { + // leaf indices starting records but referenced from symbol records + + LF_VTSHAPE=0x000a, + LF_COBOL1=0x000c, + LF_LABEL=0x000e, + LF_NULL=0x000f, + LF_NOTTRAN=0x0010, + LF_ENDPRECOMP=0x0014, // not referenced from symbol + LF_TYPESERVER_ST=0x0016, // not referenced from symbol + + // leaf indices starting records but referenced only from type records + + LF_LIST=0x0203, + LF_REFSYM=0x020c, + + LF_ENUMERATE_ST=0x0403, + + // 32-bit type index versions of leaves, all have the 0x1000 bit set + // + LF_TI16_MAX=0x1000, + + LF_MODIFIER=0x1001, + LF_POINTER=0x1002, + LF_ARRAY_ST=0x1003, + LF_CLASS_ST=0x1004, + LF_STRUCTURE_ST=0x1005, + LF_UNION_ST=0x1006, + LF_ENUM_ST=0x1007, + LF_PROCEDURE=0x1008, + LF_MFUNCTION=0x1009, + LF_COBOL0=0x100a, + LF_BARRAY=0x100b, + LF_DIMARRAY_ST=0x100c, + LF_VFTPATH=0x100d, + LF_PRECOMP_ST=0x100e, // not referenced from symbol + LF_OEM=0x100f, // oem definable type string + LF_ALIAS_ST=0x1010, // alias (typedef) type + LF_OEM2=0x1011, // oem definable type string + + // leaf indices starting records but referenced only from type records + + LF_SKIP=0x1200, + LF_ARGLIST=0x1201, + LF_DEFARG_ST=0x1202, + LF_FIELDLIST=0x1203, + LF_DERIVED=0x1204, + LF_BITFIELD=0x1205, + LF_METHODLIST=0x1206, + LF_DIMCONU=0x1207, + LF_DIMCONLU=0x1208, + LF_DIMVARU=0x1209, + LF_DIMVARLU=0x120a, + + LF_BCLASS=0x1400, + LF_VBCLASS=0x1401, + LF_IVBCLASS=0x1402, + LF_FRIENDFCN_ST=0x1403, + LF_INDEX=0x1404, + LF_MEMBER_ST=0x1405, + LF_STMEMBER_ST=0x1406, + LF_METHOD_ST=0x1407, + LF_NESTTYPE_ST=0x1408, + LF_VFUNCTAB=0x1409, + LF_FRIENDCLS=0x140a, + LF_ONEMETHOD_ST=0x140b, + LF_VFUNCOFF=0x140c, + LF_NESTTYPEEX_ST=0x140d, + LF_MEMBERMODIFY_ST=0x140e, + LF_MANAGED_ST=0x140f, + + // Types w/ SZ names + + LF_ST_MAX=0x1500, + + LF_TYPESERVER=0x1501, // not referenced from symbol + LF_ENUMERATE=0x1502, + LF_ARRAY=0x1503, + LF_CLASS=0x1504, + LF_STRUCTURE=0x1505, + LF_UNION=0x1506, + LF_ENUM=0x1507, + LF_DIMARRAY=0x1508, + LF_PRECOMP=0x1509, // not referenced from symbol + LF_ALIAS=0x150a, // alias (typedef) type + LF_DEFARG=0x150b, + LF_FRIENDFCN=0x150c, + LF_MEMBER=0x150d, + LF_STMEMBER=0x150e, + LF_METHOD=0x150f, + LF_NESTTYPE=0x1510, + LF_ONEMETHOD=0x1511, + LF_NESTTYPEEX=0x1512, + LF_MEMBERMODIFY=0x1513, + LF_MANAGED=0x1514, + LF_TYPESERVER2=0x1515, + + LF_NUMERIC=0x8000, + LF_CHAR=0x8000, + LF_SHORT=0x8001, + LF_USHORT=0x8002, + LF_LONG=0x8003, + LF_ULONG=0x8004, + LF_REAL32=0x8005, + LF_REAL64=0x8006, + LF_REAL80=0x8007, + LF_REAL128=0x8008, + LF_QUADWORD=0x8009, + LF_UQUADWORD=0x800a, + LF_COMPLEX32=0x800c, + LF_COMPLEX64=0x800d, + LF_COMPLEX80=0x800e, + LF_COMPLEX128=0x800f, + LF_VARSTRING=0x8010, + + LF_OCTWORD=0x8017, + LF_UOCTWORD=0x8018, + + LF_DECIMAL=0x8019, + LF_DATE=0x801a, + LF_UTF8STRING=0x801b, + + LF_PAD0=0xf0, + LF_PAD1=0xf1, + LF_PAD2=0xf2, + LF_PAD3=0xf3, + LF_PAD4=0xf4, + LF_PAD5=0xf5, + LF_PAD6=0xf6, + LF_PAD7=0xf7, + LF_PAD8=0xf8, + LF_PAD9=0xf9, + LF_PAD10=0xfa, + LF_PAD11=0xfb, + LF_PAD12=0xfc, + LF_PAD13=0xfd, + LF_PAD14=0xfe, + LF_PAD15=0xff, + + }; + + // end of leaf indices + + // Type enum for pointer records + // Pointers can be one of the following types + + internal enum CV_ptrtype { + CV_PTR_BASE_SEG=0x03, // based on segment + CV_PTR_BASE_VAL=0x04, // based on value of base + CV_PTR_BASE_SEGVAL=0x05, // based on segment value of base + CV_PTR_BASE_ADDR=0x06, // based on address of base + CV_PTR_BASE_SEGADDR=0x07, // based on segment address of base + CV_PTR_BASE_TYPE=0x08, // based on type + CV_PTR_BASE_SELF=0x09, // based on self + CV_PTR_NEAR32=0x0a, // 32 bit pointer + CV_PTR_64=0x0c, // 64 bit pointer + CV_PTR_UNUSEDPTR=0x0d // first unused pointer type + }; + + // Mode enum for pointers + // Pointers can have one of the following modes + + internal enum CV_ptrmode { + CV_PTR_MODE_PTR=0x00, // "normal" pointer + CV_PTR_MODE_REF=0x01, // reference + CV_PTR_MODE_PMEM=0x02, // pointer to data member + CV_PTR_MODE_PMFUNC=0x03, // pointer to member function + CV_PTR_MODE_RESERVED=0x04 // first unused pointer mode + }; + + // enumeration for pointer-to-member types + + internal enum CV_pmtype { + CV_PMTYPE_Undef=0x00, // not specified (pre VC8) + CV_PMTYPE_D_Single=0x01, // member data, single inheritance + CV_PMTYPE_D_Multiple=0x02, // member data, multiple inheritance + CV_PMTYPE_D_Virtual=0x03, // member data, virtual inheritance + CV_PMTYPE_D_General=0x04, // member data, most general + CV_PMTYPE_F_Single=0x05, // member function, single inheritance + CV_PMTYPE_F_Multiple=0x06, // member function, multiple inheritance + CV_PMTYPE_F_Virtual=0x07, // member function, virtual inheritance + CV_PMTYPE_F_General=0x08, // member function, most general + }; + + // enumeration for method properties + + internal enum CV_methodprop { + CV_MTvanilla=0x00, + CV_MTvirtual=0x01, + CV_MTstatic=0x02, + CV_MTfriend=0x03, + CV_MTintro=0x04, + CV_MTpurevirt=0x05, + CV_MTpureintro=0x06 + }; + + // enumeration for virtual shape table entries + + internal enum CV_VTS_desc { + CV_VTS_near=0x00, + CV_VTS_far=0x01, + CV_VTS_thin=0x02, + CV_VTS_outer=0x03, + CV_VTS_meta=0x04, + CV_VTS_near32=0x05, + CV_VTS_far32=0x06, + CV_VTS_unused=0x07 + }; + + // enumeration for LF_LABEL address modes + + internal enum CV_LABEL_TYPE { + CV_LABEL_NEAR=0, // near return + CV_LABEL_FAR=4 // far return + }; + + // enumeration for LF_MODIFIER values + + [Flags] + internal enum CV_modifier : ushort { + MOD_const=0x0001, + MOD_volatile=0x0002, + MOD_unaligned=0x0004, + }; + + // bit field structure describing class/struct/union/enum properties + + [Flags] + internal enum CV_prop : ushort { + packed=0x0001, // true if structure is packed + ctor=0x0002, // true if constructors or destructors present + ovlops=0x0004, // true if overloaded operators present + isnested=0x0008, // true if this is a nested class + cnested=0x0010, // true if this class contains nested types + opassign=0x0020, // true if overloaded assignment (=) + opcast=0x0040, // true if casting methods + fwdref=0x0080, // true if forward reference (incomplete defn) + scoped=0x0100, // scoped definition + } + + // class field attribute + + [Flags] + internal enum CV_fldattr { + access=0x0003, // access protection CV_access_t + mprop=0x001c, // method properties CV_methodprop_t + pseudo=0x0020, // compiler generated fcn and does not exist + noinherit=0x0040, // true if class cannot be inherited + noconstruct=0x0080, // true if class cannot be constructed + compgenx=0x0100, // compiler generated fcn and does exist + } + + // Structures to access to the type records + + internal struct TYPTYPE { + internal ushort len; + internal ushort leaf; + // byte data[]; + + // char *NextType (char * pType) { + // return (pType + ((TYPTYPE *)pType)->len + sizeof(ushort)); + // } + }; // general types record + + // memory representation of pointer to member. These representations are + // indexed by the enumeration above in the LF_POINTER record + + // representation of a 32 bit pointer to data for a class with + // or without virtual functions and no virtual bases + + internal struct CV_PDMR32_NVVFCN { + internal int mdisp; // displacement to data (NULL = 0x80000000) + }; + + // representation of a 32 bit pointer to data for a class + // with virtual bases + + internal struct CV_PDMR32_VBASE { + internal int mdisp; // displacement to data + internal int pdisp; // this pointer displacement + internal int vdisp; // vbase table displacement + // NULL = (,,0xffffffff) + }; + + // representation of a 32 bit pointer to member function for a + // class with no virtual bases and a single address point + + internal struct CV_PMFR32_NVSA { + internal uint off; // near address of function (NULL = 0L) + }; + + // representation of a 32 bit pointer to member function for a + // class with no virtual bases and multiple address points + + internal struct CV_PMFR32_NVMA { + internal uint off; // near address of function (NULL = 0L,x) + internal int disp; + }; + + // representation of a 32 bit pointer to member function for a + // class with virtual bases + + internal struct CV_PMFR32_VBASE { + internal uint off; // near address of function (NULL = 0L,x,x,x) + internal int mdisp; // displacement to data + internal int pdisp; // this pointer displacement + internal int vdisp; // vbase table displacement + }; + + ////////////////////////////////////////////////////////////////////////////// + // + // The following type records are basically variant records of the + // above structure. The "ushort leaf" of the above structure and + // the "ushort leaf" of the following type definitions are the same + // symbol. + // + + // Notes on alignment + // Alignment of the fields in most of the type records is done on the + // basis of the TYPTYPE record base. That is why in most of the lf* + // records that the type is located on what appears to + // be a offset mod 4 == 2 boundary. The exception to this rule are those + // records that are in a list (lfFieldList, lfMethodList), which are + // aligned to their own bases since they don't have the length field + // + + // Type record for LF_MODIFIER + + internal struct LeafModifier { + // internal ushort leaf; // LF_MODIFIER [TYPTYPE] + internal uint type; // (type index) modified type + internal CV_modifier attr; // modifier attribute modifier_t + }; + + // type record for LF_POINTER + + [Flags] + internal enum LeafPointerAttr : uint { + ptrtype=0x0000001f, // ordinal specifying pointer type (CV_ptrtype) + ptrmode=0x000000e0, // ordinal specifying pointer mode (CV_ptrmode) + isflat32=0x00000100, // true if 0:32 pointer + isvolatile=0x00000200, // TRUE if volatile pointer + isconst=0x00000400, // TRUE if const pointer + isunaligned=0x00000800, // TRUE if unaligned pointer + isrestrict=0x00001000, // TRUE if restricted pointer (allow agressive opts) + }; + + internal struct LeafPointer { + internal struct LeafPointerBody { + // internal ushort leaf; // LF_POINTER [TYPTYPE] + internal uint utype; // (type index) type index of the underlying type + internal LeafPointerAttr attr; + }; +#if false + union { + internal struct { + uint pmclass; // (type index) index of containing class for pointer to member + ushort pmenum; // enumeration specifying pm format (CV_pmtype) + }; + ushort bseg; // base segment if PTR_BASE_SEG + byte[] Sym; // copy of base symbol record (including length) + internal struct { + uint index; // (type index) type index if CV_PTR_BASE_TYPE + string name; // name of base type + } btype; + } pbase; +#endif + } + + // type record for LF_ARRAY + + internal struct LeafArray { + // internal ushort leaf; // LF_ARRAY [TYPTYPE] + internal uint elemtype; // (type index) type index of element type + internal uint idxtype; // (type index) type index of indexing type + internal byte[] data; // variable length data specifying size in bytes + internal string name; + }; + + // type record for LF_CLASS, LF_STRUCTURE + + internal struct LeafClass { + // internal ushort leaf; // LF_CLASS, LF_STRUCT [TYPTYPE] + internal ushort count; // count of number of elements in class + internal ushort property; // (CV_prop_t) property attribute field (prop_t) + internal uint field; // (type index) type index of LF_FIELD descriptor list + internal uint derived; // (type index) type index of derived from list if not zero + internal uint vshape; // (type index) type index of vshape table for this class + internal byte[] data; // data describing length of structure in bytes + internal string name; + }; + + // type record for LF_UNION + + internal struct LeafUnion { + // internal ushort leaf; // LF_UNION [TYPTYPE] + internal ushort count; // count of number of elements in class + internal ushort property; // (CV_prop_t) property attribute field + internal uint field; // (type index) type index of LF_FIELD descriptor list + internal byte[] data; // variable length data describing length of + internal string name; + }; + + // type record for LF_ALIAS + + internal struct LeafAlias { + // internal ushort leaf; // LF_ALIAS [TYPTYPE] + internal uint utype; // (type index) underlying type + internal string name; // alias name + }; + + // type record for LF_MANAGED + + internal struct LeafManaged { + // internal ushort leaf; // LF_MANAGED [TYPTYPE] + internal string name; // utf8, zero terminated managed type name + }; + + // type record for LF_ENUM + + internal struct LeafEnum { + // internal ushort leaf; // LF_ENUM [TYPTYPE] + internal ushort count; // count of number of elements in class + internal ushort property; // (CV_propt_t) property attribute field + internal uint utype; // (type index) underlying type of the enum + internal uint field; // (type index) type index of LF_FIELD descriptor list + internal string name; // length prefixed name of enum + }; + + // Type record for LF_PROCEDURE + + internal struct LeafProc { + // internal ushort leaf; // LF_PROCEDURE [TYPTYPE] + internal uint rvtype; // (type index) type index of return value + internal byte calltype; // calling convention (CV_call_t) + internal byte reserved; // reserved for future use + internal ushort parmcount; // number of parameters + internal uint arglist; // (type index) type index of argument list + }; + + // Type record for member function + + internal struct LeafMFunc { + // internal ushort leaf; // LF_MFUNCTION [TYPTYPE] + internal uint rvtype; // (type index) type index of return value + internal uint classtype; // (type index) type index of containing class + internal uint thistype; // (type index) type index of this pointer (model specific) + internal byte calltype; // calling convention (call_t) + internal byte reserved; // reserved for future use + internal ushort parmcount; // number of parameters + internal uint arglist; // (type index) type index of argument list + internal int thisadjust; // this adjuster (long because pad required anyway) + }; + + // type record for virtual function table shape + + internal struct LeafVTShape { + // internal ushort leaf; // LF_VTSHAPE [TYPTYPE] + internal ushort count; // number of entries in vfunctable + internal byte[] desc; // 4 bit (CV_VTS_desc) descriptors + }; + + // type record for cobol0 + + internal struct LeafCobol0 { + // internal ushort leaf; // LF_COBOL0 [TYPTYPE] + internal uint type; // (type index) parent type record index + internal byte[] data; + }; + + // type record for cobol1 + + internal struct LeafCobol1 { + // internal ushort leaf; // LF_COBOL1 [TYPTYPE] + internal byte[] data; + }; + + // type record for basic array + + internal struct LeafBArray { + // internal ushort leaf; // LF_BARRAY [TYPTYPE] + internal uint utype; // (type index) type index of underlying type + }; + + // type record for assembler labels + + internal struct LeafLabel { + // internal ushort leaf; // LF_LABEL [TYPTYPE] + internal ushort mode; // addressing mode of label + }; + + // type record for dimensioned arrays + + internal struct LeafDimArray { + // internal ushort leaf; // LF_DIMARRAY [TYPTYPE] + internal uint utype; // (type index) underlying type of the array + internal uint diminfo; // (type index) dimension information + internal string name; // length prefixed name + }; + + // type record describing path to virtual function table + + internal struct LeafVFTPath { + // internal ushort leaf; // LF_VFTPATH [TYPTYPE] + internal uint count; // count of number of bases in path + internal uint[] bases; // (type index) bases from root to leaf + }; + + // type record describing inclusion of precompiled types + + internal struct LeafPreComp { + // internal ushort leaf; // LF_PRECOMP [TYPTYPE] + internal uint start; // starting type index included + internal uint count; // number of types in inclusion + internal uint signature; // signature + internal string name; // length prefixed name of included type file + }; + + // type record describing end of precompiled types that can be + // included by another file + + internal struct LeafEndPreComp { + // internal ushort leaf; // LF_ENDPRECOMP [TYPTYPE] + internal uint signature; // signature + }; + + // type record for OEM definable type strings + + internal struct LeafOEM { + // internal ushort leaf; // LF_OEM [TYPTYPE] + internal ushort cvOEM; // MS assigned OEM identified + internal ushort recOEM; // OEM assigned type identifier + internal uint count; // count of type indices to follow + internal uint[] index; // (type index) array of type indices followed + // by OEM defined data + }; + + internal enum OEM_ID { + OEM_MS_FORTRAN90=0xF090, + OEM_ODI=0x0010, + OEM_THOMSON_SOFTWARE=0x5453, + OEM_ODI_REC_BASELIST=0x0000, + }; + + internal struct LeafOEM2 { + // internal ushort leaf; // LF_OEM2 [TYPTYPE] + internal Guid idOem; // an oem ID (Guid) + internal uint count; // count of type indices to follow + internal uint[] index; // (type index) array of type indices followed + // by OEM defined data + }; + + // type record describing using of a type server + + internal struct LeafTypeServer { + // internal ushort leaf; // LF_TYPESERVER [TYPTYPE] + internal uint signature; // signature + internal uint age; // age of database used by this module + internal string name; // length prefixed name of PDB + }; + + // type record describing using of a type server with v7 (GUID) signatures + + internal struct LeafTypeServer2 { + // internal ushort leaf; // LF_TYPESERVER2 [TYPTYPE] + internal Guid sig70; // guid signature + internal uint age; // age of database used by this module + internal string name; // length prefixed name of PDB + }; + + // description of type records that can be referenced from + // type records referenced by symbols + + // type record for skip record + + internal struct LeafSkip { + // internal ushort leaf; // LF_SKIP [TYPTYPE] + internal uint type; // (type index) next valid index + internal byte[] data; // pad data + }; + + // argument list leaf + + internal struct LeafArgList { + // internal ushort leaf; // LF_ARGLIST [TYPTYPE] + internal uint count; // number of arguments + internal uint[] arg; // (type index) number of arguments + }; + + // derived class list leaf + + internal struct LeafDerived { + // internal ushort leaf; // LF_DERIVED [TYPTYPE] + internal uint count; // number of arguments + internal uint[] drvdcls; // (type index) type indices of derived classes + }; + + // leaf for default arguments + + internal struct LeafDefArg { + // internal ushort leaf; // LF_DEFARG [TYPTYPE] + internal uint type; // (type index) type of resulting expression + internal byte[] expr; // length prefixed expression string + }; + + // list leaf + // This list should no longer be used because the utilities cannot + // verify the contents of the list without knowing what type of list + // it is. New specific leaf indices should be used instead. + + internal struct LeafList { + // internal ushort leaf; // LF_LIST [TYPTYPE] + internal byte[] data; // data format specified by indexing type + }; + + // field list leaf + // This is the header leaf for a complex list of class and structure + // subfields. + + internal struct LeafFieldList { + // internal ushort leaf; // LF_FIELDLIST [TYPTYPE] + internal char[] data; // field list sub lists + }; + + // type record for non-static methods and friends in overloaded method list + + internal struct mlMethod { + internal ushort attr; // (CV_fldattr_t) method attribute + internal ushort pad0; // internal padding, must be 0 + internal uint index; // (type index) index to type record for procedure + internal uint[] vbaseoff; // offset in vfunctable if intro virtual + }; + + internal struct LeafMethodList { + // internal ushort leaf; // LF_METHODLIST [TYPTYPE] + internal byte[] mList; // really a mlMethod type + }; + + // type record for LF_BITFIELD + + internal struct LeafBitfield { + // internal ushort leaf; // LF_BITFIELD [TYPTYPE] + internal uint type; // (type index) type of bitfield + internal byte length; + internal byte position; + }; + + // type record for dimensioned array with constant bounds + + internal struct LeafDimCon { + // internal ushort leaf; // LF_DIMCONU or LF_DIMCONLU [TYPTYPE] + internal uint typ; // (type index) type of index + internal ushort rank; // number of dimensions + internal byte[] dim; // array of dimension information with + // either upper bounds or lower/upper bound + }; + + // type record for dimensioned array with variable bounds + + internal struct LeafDimVar { + // internal ushort leaf; // LF_DIMVARU or LF_DIMVARLU [TYPTYPE] + internal uint rank; // number of dimensions + internal uint typ; // (type index) type of index + internal uint[] dim; // (type index) array of type indices for either + // variable upper bound or variable + // lower/upper bound. The count of type + // indices is rank or rank*2 depending on + // whether it is LFDIMVARU or LF_DIMVARLU. + // The referenced types must be + // LF_REFSYM or T_VOID + }; + + // type record for referenced symbol + + internal struct LeafRefSym { + // internal ushort leaf; // LF_REFSYM [TYPTYPE] + internal byte[] Sym; // copy of referenced symbol record + // (including length) + }; + + // the following are numeric leaves. They are used to indicate the + // size of the following variable length data. When the numeric + // data is a single byte less than 0x8000, then the data is output + // directly. If the data is more the 0x8000 or is a negative value, + // then the data is preceeded by the proper index. + // + + // signed character leaf + + internal struct LeafChar { + // internal ushort leaf; // LF_CHAR [TYPTYPE] + internal sbyte val; // signed 8-bit value + }; + + // signed short leaf + + internal struct LeafShort { + // internal ushort leaf; // LF_SHORT [TYPTYPE] + internal short val; // signed 16-bit value + }; + + // ushort leaf + + internal struct LeafUShort { + // internal ushort leaf; // LF_ushort [TYPTYPE] + internal ushort val; // unsigned 16-bit value + }; + + // signed (32-bit) long leaf + + internal struct LeafLong { + // internal ushort leaf; // LF_LONG [TYPTYPE] + internal int val; // signed 32-bit value + }; + + // uint leaf + + internal struct LeafULong { + // internal ushort leaf; // LF_ULONG [TYPTYPE] + internal uint val; // unsigned 32-bit value + }; + + // signed quad leaf + + internal struct LeafQuad { + // internal ushort leaf; // LF_QUAD [TYPTYPE] + internal long val; // signed 64-bit value + }; + + // unsigned quad leaf + + internal struct LeafUQuad { + // internal ushort leaf; // LF_UQUAD [TYPTYPE] + internal ulong val; // unsigned 64-bit value + }; + + // signed int128 leaf + + internal struct LeafOct { + // internal ushort leaf; // LF_OCT [TYPTYPE] + internal ulong val0; + internal ulong val1; // signed 128-bit value + }; + + // unsigned int128 leaf + + internal struct LeafUOct { + // internal ushort leaf; // LF_UOCT [TYPTYPE] + internal ulong val0; + internal ulong val1; // unsigned 128-bit value + }; + + // real 32-bit leaf + + internal struct LeafReal32 { + // internal ushort leaf; // LF_REAL32 [TYPTYPE] + internal float val; // 32-bit real value + }; + + // real 64-bit leaf + + internal struct LeafReal64 { + // internal ushort leaf; // LF_REAL64 [TYPTYPE] + internal double val; // 64-bit real value + }; + + // real 80-bit leaf + + internal struct LeafReal80 { + // internal ushort leaf; // LF_REAL80 [TYPTYPE] + internal FLOAT10 val; // real 80-bit value + }; + + // real 128-bit leaf + + internal struct LeafReal128 { + // internal ushort leaf; // LF_REAL128 [TYPTYPE] + internal ulong val0; + internal ulong val1; // real 128-bit value + }; + + // complex 32-bit leaf + + internal struct LeafCmplx32 { + // internal ushort leaf; // LF_COMPLEX32 [TYPTYPE] + internal float val_real; // real component + internal float val_imag; // imaginary component + }; + + // complex 64-bit leaf + + internal struct LeafCmplx64 { + // internal ushort leaf; // LF_COMPLEX64 [TYPTYPE] + internal double val_real; // real component + internal double val_imag; // imaginary component + }; + + // complex 80-bit leaf + + internal struct LeafCmplx80 { + // internal ushort leaf; // LF_COMPLEX80 [TYPTYPE] + internal FLOAT10 val_real; // real component + internal FLOAT10 val_imag; // imaginary component + }; + + // complex 128-bit leaf + + internal struct LeafCmplx128 { + // internal ushort leaf; // LF_COMPLEX128 [TYPTYPE] + internal ulong val0_real; + internal ulong val1_real; // real component + internal ulong val0_imag; + internal ulong val1_imag; // imaginary component + }; + + // variable length numeric field + + internal struct LeafVarString { + // internal ushort leaf; // LF_VARSTRING [TYPTYPE] + internal ushort len; // length of value in bytes + internal byte[] value; // value + }; + + // index leaf - contains type index of another leaf + // a major use of this leaf is to allow the compilers to emit a + // long complex list (LF_FIELD) in smaller pieces. + + internal struct LeafIndex { + // internal ushort leaf; // LF_INDEX [TYPTYPE] + internal ushort pad0; // internal padding, must be 0 + internal uint index; // (type index) type index of referenced leaf + }; + + // subfield record for base class field + + internal struct LeafBClass { + // internal ushort leaf; // LF_BCLASS [TYPTYPE] + internal ushort attr; // (CV_fldattr_t) attribute + internal uint index; // (type index) type index of base class + internal byte[] offset; // variable length offset of base within class + }; + + // subfield record for direct and indirect virtual base class field + + internal struct LeafVBClass { + // internal ushort leaf; // LF_VBCLASS | LV_IVBCLASS [TYPTYPE] + internal ushort attr; // (CV_fldattr_t) attribute + internal uint index; // (type index) type index of direct virtual base class + internal uint vbptr; // (type index) type index of virtual base pointer + internal byte[] vbpoff; // virtual base pointer offset from address point + // followed by virtual base offset from vbtable + }; + + // subfield record for friend class + + internal struct LeafFriendCls { + // internal ushort leaf; // LF_FRIENDCLS [TYPTYPE] + internal ushort pad0; // internal padding, must be 0 + internal uint index; // (type index) index to type record of friend class + }; + + // subfield record for friend function + + internal struct LeafFriendFcn { + // internal ushort leaf; // LF_FRIENDFCN [TYPTYPE] + internal ushort pad0; // internal padding, must be 0 + internal uint index; // (type index) index to type record of friend function + internal string name; // name of friend function + }; + + // subfield record for non-static data members + + internal struct LeafMember { + // internal ushort leaf; // LF_MEMBER [TYPTYPE] + internal ushort attr; // (CV_fldattr_t)attribute mask + internal uint index; // (type index) index of type record for field + internal byte[] offset; // variable length offset of field + internal string name; // length prefixed name of field + }; + + // type record for static data members + + internal struct LeafSTMember { + // internal ushort leaf; // LF_STMEMBER [TYPTYPE] + internal ushort attr; // (CV_fldattr_t) attribute mask + internal uint index; // (type index) index of type record for field + internal string name; // length prefixed name of field + }; + + // subfield record for virtual function table pointer + + internal struct LeafVFuncTab { + // internal ushort leaf; // LF_VFUNCTAB [TYPTYPE] + internal ushort pad0; // internal padding, must be 0 + internal uint type; // (type index) type index of pointer + }; + + // subfield record for virtual function table pointer with offset + + internal struct LeafVFuncOff { + // internal ushort leaf; // LF_VFUNCOFF [TYPTYPE] + internal ushort pad0; // internal padding, must be 0. + internal uint type; // (type index) type index of pointer + internal int offset; // offset of virtual function table pointer + }; + + // subfield record for overloaded method list + + internal struct LeafMethod { + // internal ushort leaf; // LF_METHOD [TYPTYPE] + internal ushort count; // number of occurrences of function + internal uint mList; // (type index) index to LF_METHODLIST record + internal string name; // length prefixed name of method + }; + + // subfield record for nonoverloaded method + + internal struct LeafOneMethod { + // internal ushort leaf; // LF_ONEMETHOD [TYPTYPE] + internal ushort attr; // (CV_fldattr_t) method attribute + internal uint index; // (type index) index to type record for procedure + internal uint[] vbaseoff; // offset in vfunctable if intro virtual + internal string name; + }; + + // subfield record for enumerate + + internal struct LeafEnumerate { + // internal ushort leaf; // LF_ENUMERATE [TYPTYPE] + internal ushort attr; // (CV_fldattr_t) access + internal byte[] value; // variable length value field + internal string name; + }; + + // type record for nested (scoped) type definition + + internal struct LeafNestType { + // internal ushort leaf; // LF_NESTTYPE [TYPTYPE] + internal ushort pad0; // internal padding, must be 0 + internal uint index; // (type index) index of nested type definition + internal string name; // length prefixed type name + }; + + // type record for nested (scoped) type definition, with attributes + // new records for vC v5.0, no need to have 16-bit ti versions. + + internal struct LeafNestTypeEx { + // internal ushort leaf; // LF_NESTTYPEEX [TYPTYPE] + internal ushort attr; // (CV_fldattr_t) member access + internal uint index; // (type index) index of nested type definition + internal string name; // length prefixed type name + }; + + // type record for modifications to members + + internal struct LeafMemberModify { + // internal ushort leaf; // LF_MEMBERMODIFY [TYPTYPE] + internal ushort attr; // (CV_fldattr_t) the new attributes + internal uint index; // (type index) index of base class type definition + internal string name; // length prefixed member name + }; + + // type record for pad leaf + + internal struct LeafPad { + internal byte leaf; + }; + + // Symbol definitions + + internal enum SYM { + S_END=0x0006, // Block, procedure, "with" or thunk end + S_OEM=0x0404, // OEM defined symbol + + S_REGISTER_ST=0x1001, // Register variable + S_CONSTANT_ST=0x1002, // constant symbol + S_UDT_ST=0x1003, // User defined type + S_COBOLUDT_ST=0x1004, // special UDT for cobol that does not symbol pack + S_MANYREG_ST=0x1005, // multiple register variable + S_BPREL32_ST=0x1006, // BP-relative + S_LDATA32_ST=0x1007, // Module-local symbol + S_GDATA32_ST=0x1008, // Global data symbol + S_PUB32_ST=0x1009, // a internal symbol (CV internal reserved) + S_LPROC32_ST=0x100a, // Local procedure start + S_GPROC32_ST=0x100b, // Global procedure start + S_VFTABLE32=0x100c, // address of virtual function table + S_REGREL32_ST=0x100d, // register relative address + S_LTHREAD32_ST=0x100e, // local thread storage + S_GTHREAD32_ST=0x100f, // global thread storage + + S_LPROCMIPS_ST=0x1010, // Local procedure start + S_GPROCMIPS_ST=0x1011, // Global procedure start + + // new symbol records for edit and continue information + + S_FRAMEPROC=0x1012, // extra frame and proc information + S_COMPILE2_ST=0x1013, // extended compile flags and info + + // new symbols necessary for 16-bit enumerates of IA64 registers + // and IA64 specific symbols + + S_MANYREG2_ST=0x1014, // multiple register variable + S_LPROCIA64_ST=0x1015, // Local procedure start (IA64) + S_GPROCIA64_ST=0x1016, // Global procedure start (IA64) + + // Local symbols for IL + S_LOCALSLOT_ST=0x1017, // local IL sym with field for local slot index + S_PARAMSLOT_ST=0x1018, // local IL sym with field for parameter slot index + + S_ANNOTATION=0x1019, // Annotation string literals + + // symbols to support managed code debugging + S_GMANPROC_ST=0x101a, // Global proc + S_LMANPROC_ST=0x101b, // Local proc + S_RESERVED1=0x101c, // reserved + S_RESERVED2=0x101d, // reserved + S_RESERVED3=0x101e, // reserved + S_RESERVED4=0x101f, // reserved + S_LMANDATA_ST=0x1020, + S_GMANDATA_ST=0x1021, + S_MANFRAMEREL_ST=0x1022, + S_MANREGISTER_ST=0x1023, + S_MANSLOT_ST=0x1024, + S_MANMANYREG_ST=0x1025, + S_MANREGREL_ST=0x1026, + S_MANMANYREG2_ST=0x1027, + S_MANTYPREF=0x1028, // Index for type referenced by name from metadata + S_UNAMESPACE_ST=0x1029, // Using namespace + + // Symbols w/ SZ name fields. All name fields contain utf8 encoded strings. + S_ST_MAX=0x1100, // starting point for SZ name symbols + + S_OBJNAME=0x1101, // path to object file name + S_THUNK32=0x1102, // Thunk Start + S_BLOCK32=0x1103, // block start + S_WITH32=0x1104, // with start + S_LABEL32=0x1105, // code label + S_REGISTER=0x1106, // Register variable + S_CONSTANT=0x1107, // constant symbol + S_UDT=0x1108, // User defined type + S_COBOLUDT=0x1109, // special UDT for cobol that does not symbol pack + S_MANYREG=0x110a, // multiple register variable + S_BPREL32=0x110b, // BP-relative + S_LDATA32=0x110c, // Module-local symbol + S_GDATA32=0x110d, // Global data symbol + S_PUB32=0x110e, // a internal symbol (CV internal reserved) + S_LPROC32=0x110f, // Local procedure start + S_GPROC32=0x1110, // Global procedure start + S_REGREL32=0x1111, // register relative address + S_LTHREAD32=0x1112, // local thread storage + S_GTHREAD32=0x1113, // global thread storage + + S_LPROCMIPS=0x1114, // Local procedure start + S_GPROCMIPS=0x1115, // Global procedure start + S_COMPILE2=0x1116, // extended compile flags and info + S_MANYREG2=0x1117, // multiple register variable + S_LPROCIA64=0x1118, // Local procedure start (IA64) + S_GPROCIA64=0x1119, // Global procedure start (IA64) + S_LOCALSLOT=0x111a, // local IL sym with field for local slot index + S_SLOT=S_LOCALSLOT, // alias for LOCALSLOT + S_PARAMSLOT=0x111b, // local IL sym with field for parameter slot index + + // symbols to support managed code debugging + S_LMANDATA=0x111c, + S_GMANDATA=0x111d, + S_MANFRAMEREL=0x111e, + S_MANREGISTER=0x111f, + S_MANSLOT=0x1120, + S_MANMANYREG=0x1121, + S_MANREGREL=0x1122, + S_MANMANYREG2=0x1123, + S_UNAMESPACE=0x1124, // Using namespace + + // ref symbols with name fields + S_PROCREF=0x1125, // Reference to a procedure + S_DATAREF=0x1126, // Reference to data + S_LPROCREF=0x1127, // Local Reference to a procedure + S_ANNOTATIONREF=0x1128, // Reference to an S_ANNOTATION symbol + S_TOKENREF=0x1129, // Reference to one of the many MANPROCSYM's + + // continuation of managed symbols + S_GMANPROC=0x112a, // Global proc + S_LMANPROC=0x112b, // Local proc + + // short, light-weight thunks + S_TRAMPOLINE=0x112c, // trampoline thunks + S_MANCONSTANT=0x112d, // constants with metadata type info + + // native attributed local/parms + S_ATTR_FRAMEREL=0x112e, // relative to virtual frame ptr + S_ATTR_REGISTER=0x112f, // stored in a register + S_ATTR_REGREL=0x1130, // relative to register (alternate frame ptr) + S_ATTR_MANYREG=0x1131, // stored in >1 register + + // Separated code (from the compiler) support + S_SEPCODE=0x1132, + + S_LOCAL=0x1133, // defines a local symbol in optimized code + S_DEFRANGE=0x1134, // defines a single range of addresses in which symbol can be evaluated + S_DEFRANGE2=0x1135, // defines ranges of addresses in which symbol can be evaluated + + S_SECTION=0x1136, // A COFF section in a PE executable + S_COFFGROUP=0x1137, // A COFF group + S_EXPORT=0x1138, // A export + + S_CALLSITEINFO=0x1139, // Indirect call site information + S_FRAMECOOKIE=0x113a, // Security cookie information + + S_DISCARDED=0x113b, // Discarded by LINK /OPT:REF (experimental, see richards) + + S_RECTYPE_MAX, // one greater than last + S_RECTYPE_LAST=S_RECTYPE_MAX - 1, + + }; + + // enum describing compile flag ambient data model + + internal enum CV_CFL_DATA { + CV_CFL_DNEAR=0x00, + CV_CFL_DFAR=0x01, + CV_CFL_DHUGE=0x02 + }; + + // enum describing compile flag ambiant code model + + internal enum CV_CFL_CODE { + CV_CFL_CNEAR=0x00, + CV_CFL_CFAR=0x01, + CV_CFL_CHUGE=0x02 + }; + + // enum describing compile flag target floating point package + + internal enum CV_CFL_FPKG { + CV_CFL_NDP=0x00, + CV_CFL_EMU=0x01, + CV_CFL_ALT=0x02 + }; + + // enum describing function return method + + [Flags] + internal enum CV_PROCFLAGS : byte { + CV_PFLAG_NOFPO=0x01, // frame pointer present + CV_PFLAG_INT=0x02, // interrupt return + CV_PFLAG_FAR=0x04, // far return + CV_PFLAG_NEVER=0x08, // function does not return + CV_PFLAG_NOTREACHED=0x10, // label isn't fallen into + CV_PFLAG_CUST_CALL=0x20, // custom calling convention + CV_PFLAG_NOINLINE=0x40, // function marked as noinline + CV_PFLAG_OPTDBGINFO=0x80, // function has debug information for optimized code + }; + + // Extended proc flags + // + internal struct CV_EXPROCFLAGS { + internal byte flags; // (CV_PROCFLAGS) + internal byte reserved; // must be zero + }; + + // local variable flags + [Flags] + internal enum CV_LVARFLAGS : ushort { + fIsParam=0x0001, // variable is a parameter + fAddrTaken=0x0002, // address is taken + fCompGenx=0x0004, // variable is compiler generated + fIsAggregate=0x0008, // the symbol is splitted in temporaries, + // which are treated by compiler as + // independent entities + fIsAggregated=0x0010, // Counterpart of fIsAggregate - tells + // that it is a part of a fIsAggregate symbol + fIsAliased=0x0020, // variable has multiple simultaneous lifetimes + fIsAlias=0x0040, // represents one of the multiple simultaneous lifetimes + }; + + // represents an address range, used for optimized code debug info + internal struct CV_lvar_addr_range { // defines a range of addresses + internal uint offStart; + internal ushort isectStart; + internal uint cbRange; + }; + + // enum describing function data return method + + internal enum CV_GENERIC_STYLE { + CV_GENERIC_VOID=0x00, // void return type + CV_GENERIC_REG=0x01, // return data is in registers + CV_GENERIC_ICAN=0x02, // indirect caller allocated near + CV_GENERIC_ICAF=0x03, // indirect caller allocated far + CV_GENERIC_IRAN=0x04, // indirect returnee allocated near + CV_GENERIC_IRAF=0x05, // indirect returnee allocated far + CV_GENERIC_UNUSED=0x06 // first unused + }; + + [Flags] + internal enum CV_GENERIC_FLAG : ushort { + cstyle=0x0001, // true push varargs right to left + rsclean=0x0002, // true if returnee stack cleanup + }; + + // flag bitfields for separated code attributes + + [Flags] + internal enum CV_SEPCODEFLAGS : uint { + fIsLexicalScope=0x00000001, // S_SEPCODE doubles as lexical scope + fReturnsToParent=0x00000002, // code frag returns to parent + }; + + // Generic layout for symbol records + + internal struct SYMTYPE { + internal ushort reclen; // Record length + internal ushort rectyp; // Record type + // byte data[CV_ZEROLEN]; + // SYMTYPE *NextSym (SYMTYPE * pSym) { + // return (SYMTYPE *) ((char *)pSym + pSym->reclen + sizeof(ushort)); + // } + }; + + // non-model specific symbol types + + internal struct RegSym { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_REGISTER + internal uint typind; // (type index) Type index or Metadata token + internal ushort reg; // register enumerate + internal string name; // Length-prefixed name + }; + + internal struct AttrRegSym { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_MANREGISTER | S_ATTR_REGISTER + internal uint typind; // (type index) Type index or Metadata token + internal uint offCod; // first code address where var is live + internal ushort segCod; + internal ushort flags; // (CV_LVARFLAGS)local var flags + internal ushort reg; // register enumerate + internal string name; // Length-prefixed name + }; + + internal struct ManyRegSym { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_MANYREG + internal uint typind; // (type index) Type index or metadata token + internal byte count; // count of number of registers + internal byte[] reg; // count register enumerates, most-sig first + internal string name; // length-prefixed name. + }; + + internal struct ManyRegSym2 { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_MANYREG2 + internal uint typind; // (type index) Type index or metadata token + internal ushort count; // count of number of registers, + internal ushort[] reg; // count register enumerates, most-sig first + internal string name; // length-prefixed name. + }; + + internal struct AttrManyRegSym { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_MANMANYREG + internal uint typind; // (type index) Type index or metadata token + internal uint offCod; // first code address where var is live + internal ushort segCod; + internal ushort flags; // (CV_LVARFLAGS)local var flags + internal byte count; // count of number of registers + internal byte[] reg; // count register enumerates, most-sig first + internal string name; // utf-8 encoded zero terminate name + }; + + internal struct AttrManyRegSym2 { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_MANMANYREG2 | S_ATTR_MANYREG + internal uint typind; // (type index) Type index or metadata token + internal uint offCod; // first code address where var is live + internal ushort segCod; + internal ushort flags; // (CV_LVARFLAGS)local var flags + internal ushort count; // count of number of registers + internal ushort[] reg; // count register enumerates, most-sig first + internal string name; // utf-8 encoded zero terminate name + }; + + internal struct ConstSym { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_CONSTANT or S_MANCONSTANT + internal uint typind; // (type index) Type index (containing enum if enumerate) or metadata token + internal ushort value; // numeric leaf containing value + internal string name; // Length-prefixed name + }; + + internal struct UdtSym { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_UDT | S_COBOLUDT + internal uint typind; // (type index) Type index + internal string name; // Length-prefixed name + }; + + internal struct ManyTypRef { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_MANTYPREF + internal uint typind; // (type index) Type index + }; + + internal struct SearchSym { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_SSEARCH + internal uint startsym; // offset of the procedure + internal ushort seg; // segment of symbol + }; + + [Flags] + internal enum CFLAGSYM_FLAGS : ushort { + pcode=0x0001, // true if pcode present + floatprec=0x0006, // floating precision + floatpkg=0x0018, // float package + ambdata=0x00e0, // ambient data model + ambcode=0x0700, // ambient code model + mode32=0x0800, // true if compiled 32 bit mode + }; + + internal struct CFlagSym { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_COMPILE + internal byte machine; // target processor + internal byte language; // language index + internal ushort flags; // (CFLAGSYM_FLAGS) + internal string ver; // Length-prefixed compiler version string + }; + + [Flags] + internal enum COMPILESYM_FLAGS : uint { + iLanguage=0x000000ff, // language index + fEC=0x00000100, // compiled for E/C + fNoDbgInfo=0x00000200, // not compiled with debug info + fLTCG=0x00000400, // compiled with LTCG + fNoDataAlign=0x00000800, // compiled with -Bzalign + fManagedPresent=0x00001000, // managed code/data present + fSecurityChecks=0x00002000, // compiled with /GS + fHotPatch=0x00004000, // compiled with /hotpatch + fCVTCIL=0x00008000, // converted with CVTCIL + fMSILModule=0x00010000, // MSIL netmodule + }; + + internal struct CompileSym { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_COMPILE2 + internal uint flags; // (COMPILESYM_FLAGS) + internal ushort machine; // target processor + internal ushort verFEMajor; // front end major version # + internal ushort verFEMinor; // front end minor version # + internal ushort verFEBuild; // front end build version # + internal ushort verMajor; // back end major version # + internal ushort verMinor; // back end minor version # + internal ushort verBuild; // back end build version # + internal string verSt; // Length-prefixed compiler version string, followed + internal string[] verArgs; // block of zero terminated strings, ended by double-zero. + }; + + internal struct ObjNameSym { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_OBJNAME + internal uint signature; // signature + internal string name; // Length-prefixed name + }; + + internal struct EndArgSym { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_ENDARG + }; + + internal struct ReturnSym { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_RETURN + internal CV_GENERIC_FLAG flags; // flags + internal byte style; // CV_GENERIC_STYLE return style + // followed by return method data + }; + + internal struct EntryThisSym { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_ENTRYTHIS + internal byte thissym; // symbol describing this pointer on entry + }; + + internal struct BpRelSym32 { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_BPREL32 + internal int off; // BP-relative offset + internal uint typind; // (type index) Type index or Metadata token + internal string name; // Length-prefixed name + }; + + internal struct FrameRelSym { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_MANFRAMEREL | S_ATTR_FRAMEREL + internal int off; // Frame relative offset + internal uint typind; // (type index) Type index or Metadata token + internal uint offCod; // first code address where var is live + internal ushort segCod; + internal ushort flags; // (CV_LVARFLAGS)local var flags + internal string name; // Length-prefixed name + }; + + internal struct SlotSym32 { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_LOCALSLOT or S_PARAMSLOT + internal uint index; // slot index + internal uint typind; // (type index) Type index or Metadata token + internal string name; // Length-prefixed name + }; + + internal struct AttrSlotSym { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_MANSLOT + internal uint index; // slot index + internal uint typind; // (type index) Type index or Metadata token + internal uint offCod; // first code address where var is live + internal ushort segCod; + internal ushort flags; // (CV_LVARFLAGS)local var flags + internal string name; // Length-prefixed name + + }; + + internal struct AnnotationSym { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_ANNOTATION + internal uint off; + internal ushort seg; + internal ushort csz; // Count of zero terminated annotation strings + internal string[] rgsz; // Sequence of zero terminated annotation strings + }; + + internal struct DatasSym32 { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_LDATA32, S_GDATA32 or S_PUB32, S_LMANDATA, S_GMANDATA + internal uint typind; // (type index) Type index, or Metadata token if a managed symbol + internal uint off; + internal ushort seg; + internal string name; // Length-prefixed name + }; + + [Flags] + internal enum CV_PUBSYMFLAGS : uint { + fNone=0, + fCode=0x00000001, // set if internal symbol refers to a code address + fFunction=0x00000002, // set if internal symbol is a function + fManaged=0x00000004, // set if managed code (native or IL) + fMSIL=0x00000008, // set if managed IL code + }; + + internal struct PubSym32 { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_PUB32 + internal uint flags; // (CV_PUBSYMFLAGS) + internal uint off; + internal ushort seg; + internal string name; // Length-prefixed name + }; + + internal struct ProcSym32 { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_GPROC32 or S_LPROC32 + internal uint parent; // pointer to the parent + internal uint end; // pointer to this blocks end + internal uint next; // pointer to next symbol + internal uint len; // Proc length + internal uint dbgStart; // Debug start offset + internal uint dbgEnd; // Debug end offset + internal uint typind; // (type index) Type index + internal uint off; + internal ushort seg; + internal byte flags; // (CV_PROCFLAGS) Proc flags + internal string name; // Length-prefixed name + }; + + internal struct ManProcSym { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_GMANPROC, S_LMANPROC, S_GMANPROCIA64 or S_LMANPROCIA64 + internal uint parent; // pointer to the parent + internal uint end; // pointer to this blocks end + internal uint next; // pointer to next symbol + internal uint len; // Proc length + internal uint dbgStart; // Debug start offset + internal uint dbgEnd; // Debug end offset + internal uint token; // COM+ metadata token for method + internal uint off; + internal ushort seg; + internal byte flags; // (CV_PROCFLAGS) Proc flags + internal ushort retReg; // Register return value is in (may not be used for all archs) + internal string name; // optional name field + }; + + internal struct ManProcSymMips { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_GMANPROCMIPS or S_LMANPROCMIPS + internal uint parent; // pointer to the parent + internal uint end; // pointer to this blocks end + internal uint next; // pointer to next symbol + internal uint len; // Proc length + internal uint dbgStart; // Debug start offset + internal uint dbgEnd; // Debug end offset + internal uint regSave; // int register save mask + internal uint fpSave; // fp register save mask + internal uint intOff; // int register save offset + internal uint fpOff; // fp register save offset + internal uint token; // COM+ token type + internal uint off; + internal ushort seg; + internal byte retReg; // Register return value is in + internal byte frameReg; // Frame pointer register + internal string name; // optional name field + }; + + internal struct ThunkSym32 { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_THUNK32 + internal uint parent; // pointer to the parent + internal uint end; // pointer to this blocks end + internal uint next; // pointer to next symbol + internal uint off; + internal ushort seg; + internal ushort len; // length of thunk + internal byte ord; // THUNK_ORDINAL specifying type of thunk + internal string name; // Length-prefixed name + internal byte[] variant; // variant portion of thunk + }; + + internal enum TRAMP { // Trampoline subtype + trampIncremental, // incremental thunks + trampBranchIsland, // Branch island thunks + }; + + internal struct TrampolineSym { // Trampoline thunk symbol + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_TRAMPOLINE + internal ushort trampType; // trampoline sym subtype + internal ushort cbThunk; // size of the thunk + internal uint offThunk; // offset of the thunk + internal uint offTarget; // offset of the target of the thunk + internal ushort sectThunk; // section index of the thunk + internal ushort sectTarget; // section index of the target of the thunk + }; + + internal struct LabelSym32 { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_LABEL32 + internal uint off; + internal ushort seg; + internal byte flags; // (CV_PROCFLAGS) flags + internal string name; // Length-prefixed name + }; + + internal struct BlockSym32 { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_BLOCK32 + internal uint parent; // pointer to the parent + internal uint end; // pointer to this blocks end + internal uint len; // Block length + internal uint off; // Offset in code segment + internal ushort seg; // segment of label + internal string name; // Length-prefixed name + }; + + internal struct WithSym32 { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_WITH32 + internal uint parent; // pointer to the parent + internal uint end; // pointer to this blocks end + internal uint len; // Block length + internal uint off; // Offset in code segment + internal ushort seg; // segment of label + internal string expr; // Length-prefixed expression string + }; + + internal struct VpathSym32 { + // internal ushort reclen; // record length + // internal ushort rectyp; // S_VFTABLE32 + internal uint root; // (type index) type index of the root of path + internal uint path; // (type index) type index of the path record + internal uint off; // offset of virtual function table + internal ushort seg; // segment of virtual function table + }; + + internal struct RegRel32 { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_REGREL32 + internal uint off; // offset of symbol + internal uint typind; // (type index) Type index or metadata token + internal ushort reg; // register index for symbol + internal string name; // Length-prefixed name + }; + + internal struct AttrRegRel { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_MANREGREL | S_ATTR_REGREL + internal uint off; // offset of symbol + internal uint typind; // (type index) Type index or metadata token + internal ushort reg; // register index for symbol + internal uint offCod; // first code address where var is live + internal ushort segCod; + internal ushort flags; // (CV_LVARFLAGS)local var flags + internal string name; // Length-prefixed name + }; + + internal struct ThreadSym32 { + // internal ushort reclen; // record length + // internal ushort rectyp; // S_LTHREAD32 | S_GTHREAD32 + internal uint typind; // (type index) type index + internal uint off; // offset into thread storage + internal ushort seg; // segment of thread storage + internal string name; // length prefixed name + }; + + internal struct Slink32 { + // internal ushort reclen; // record length + // internal ushort rectyp; // S_SLINK32 + internal uint framesize; // frame size of parent procedure + internal int off; // signed offset where the static link was saved relative to the value of reg + internal ushort reg; + }; + + internal struct ProcSymMips { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_GPROCMIPS or S_LPROCMIPS + internal uint parent; // pointer to the parent + internal uint end; // pointer to this blocks end + internal uint next; // pointer to next symbol + internal uint len; // Proc length + internal uint dbgStart; // Debug start offset + internal uint dbgEnd; // Debug end offset + internal uint regSave; // int register save mask + internal uint fpSave; // fp register save mask + internal uint intOff; // int register save offset + internal uint fpOff; // fp register save offset + internal uint typind; // (type index) Type index + internal uint off; // Symbol offset + internal ushort seg; // Symbol segment + internal byte retReg; // Register return value is in + internal byte frameReg; // Frame pointer register + internal string name; // Length-prefixed name + }; + + internal struct ProcSymIa64 { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_GPROCIA64 or S_LPROCIA64 + internal uint parent; // pointer to the parent + internal uint end; // pointer to this blocks end + internal uint next; // pointer to next symbol + internal uint len; // Proc length + internal uint dbgStart; // Debug start offset + internal uint dbgEnd; // Debug end offset + internal uint typind; // (type index) Type index + internal uint off; // Symbol offset + internal ushort seg; // Symbol segment + internal ushort retReg; // Register return value is in + internal byte flags; // (CV_PROCFLAGS) Proc flags + internal string name; // Length-prefixed name + }; + + internal struct RefSym { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_PROCREF_ST, S_DATAREF_ST, or S_LPROCREF_ST + internal uint sumName; // SUC of the name + internal uint ibSym; // Offset of actual symbol in $$Symbols + internal ushort imod; // Module containing the actual symbol + internal ushort usFill; // align this record + }; + + internal struct RefSym2 { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_PROCREF, S_DATAREF, or S_LPROCREF + internal uint sumName; // SUC of the name + internal uint ibSym; // Offset of actual symbol in $$Symbols + internal ushort imod; // Module containing the actual symbol + internal string name; // hidden name made a first class member + }; + + internal struct AlignSym { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_ALIGN + }; + + internal struct OemSymbol { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_OEM + internal Guid idOem; // an oem ID (GUID) + internal uint typind; // (type index) Type index + internal byte[] rgl; // user data, force 4-byte alignment + }; + + [Flags] + internal enum FRAMEPROCSYM_FLAGS : uint { + fHasAlloca=0x00000001, // function uses _alloca() + fHasSetJmp=0x00000002, // function uses setjmp() + fHasLongJmp=0x00000004, // function uses longjmp() + fHasInlAsm=0x00000008, // function uses inline asm + fHasEH=0x00000010, // function has EH states + fInlSpec=0x00000020, // function was speced as inline + fHasSEH=0x00000040, // function has SEH + fNaked=0x00000080, // function is __declspec(naked) + fSecurityChecks=0x00000100, // function has buffer security check introduced by /GS. + fAsyncEH=0x00000200, // function compiled with /EHa + fGSNoStackOrdering=0x00000400, // function has /GS buffer checks, but stack ordering couldn't be done + fWasInlined=0x00000800, // function was inlined within another function + }; + + internal struct FrameProcSym { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_FRAMEPROC + internal uint cbFrame; // count of bytes of total frame of procedure + internal uint cbPad; // count of bytes of padding in the frame + internal uint offPad; // offset (rel to frame) to where padding starts + internal uint cbSaveRegs; // count of bytes of callee save registers + internal uint offExHdlr; // offset of exception handler + internal ushort secExHdlr; // section id of exception handler + internal uint flags; // (FRAMEPROCSYM_FLAGS) + } + + internal struct UnamespaceSym { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_UNAMESPACE + internal string name; // name + }; + + internal struct SepCodSym { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_SEPCODE + internal uint parent; // pointer to the parent + internal uint end; // pointer to this block's end + internal uint length; // count of bytes of this block + internal uint scf; // (CV_SEPCODEFLAGS) flags + internal uint off; // sec:off of the separated code + internal uint offParent; // secParent:offParent of the enclosing scope + internal ushort sec; // (proc, block, or sepcode) + internal ushort secParent; + }; + + internal struct LocalSym { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_LOCAL + internal uint id; // id of the local + internal uint typind; // (type index) type index + internal ushort flags; // (CV_LVARFLAGS) local var flags + internal uint idParent; // This is is parent variable - fIsAggregated or fIsAlias + internal uint offParent; // Offset in parent variable - fIsAggregated + + internal uint expr; // NI of expression that this temp holds + internal uint pad0; // pad, must be zero + internal uint pad1; // pad, must be zero + + internal string name; // Name of this symbol. + } + + internal struct DefRangeSym { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_DEFRANGE + + internal uint id; // ID of the local symbol for which this formula holds + internal uint program; // program to evaluate the value of the symbol + + internal CV_lvar_addr_range range; // Range of addresses where this program is valid + }; + + internal struct DefRangeSym2 { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_DEFRANGE2 + + internal uint id; // ID of the local symbol for which this formula holds + internal uint program; // program to evaluate the value of the symbol + + internal ushort count; // count of CV_lvar_addr_range records following + internal CV_lvar_addr_range[] range;// Range of addresses where this program is valid + }; + + internal struct SectionSym { + // internal ushort reclen // Record length + // internal ushort rectyp; // S_SECTION + + internal ushort isec; // Section number + internal byte align; // Alignment of this section (power of 2) + internal byte bReserved; // Reserved. Must be zero. + internal uint rva; + internal uint cb; + internal uint characteristics; + internal string name; // name + }; + + internal struct CoffGroupSym { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_COFFGROUP + + internal uint cb; + internal uint characteristics; + internal uint off; // Symbol offset + internal ushort seg; // Symbol segment + internal string name; // name + }; + + [Flags] + internal enum EXPORTSYM_FLAGS : ushort { + fConstant=0x0001, // CONSTANT + fData=0x0002, // DATA + fPrivate=0x0004, // PRIVATE + fNoName=0x0008, // NONAME + fOrdinal=0x0010, // Ordinal was explicitly assigned + fForwarder=0x0020, // This is a forwarder + } + + internal struct ExportSym { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_EXPORT + + internal ushort ordinal; + internal ushort flags; // (EXPORTSYM_FLAGS) + internal string name; // name of + }; + + // + // Symbol for describing indirect calls when they are using + // a function pointer cast on some other type or temporary. + // Typical content will be an LF_POINTER to an LF_PROCEDURE + // type record that should mimic an actual variable with the + // function pointer type in question. + // + // Since the compiler can sometimes tail-merge a function call + // through a function pointer, there may be more than one + // S_CALLSITEINFO record at an address. This is similar to what + // you could do in your own code by: + // + // if (expr) + // pfn = &function1; + // else + // pfn = &function2; + // + // (*pfn)(arg list); + // + + internal struct CallsiteInfo { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_CALLSITEINFO + internal int off; // offset of call site + internal ushort ect; // section index of call site + internal ushort pad0; // alignment padding field, must be zero + internal uint typind; // (type index) type index describing function signature + }; + + // Frame cookie information + + internal enum CV_cookietype { + CV_COOKIETYPE_COPY=0, + CV_COOKIETYPE_XOR_SP, + CV_COOKIETYPE_XOR_BP, + CV_COOKIETYPE_XOR_R13, + }; + + // Symbol for describing security cookie's position and type + // (raw, xor'd with esp, xor'd with ebp). + + internal struct FrameCookie { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_FRAMECOOKIE + internal int off; // Frame relative offset + internal ushort reg; // Register index + internal int cookietype; // (CV_cookietype) Type of the cookie + internal byte flags; // Flags describing this cookie + }; + + internal enum CV_DISCARDED : uint { + CV_DISCARDED_UNKNOWN=0, + CV_DISCARDED_NOT_SELECTED=1, + CV_DISCARDED_NOT_REFERENCED=2, + }; + + internal struct DiscardedSym { + // internal ushort reclen; // Record length [SYMTYPE] + // internal ushort rectyp; // S_DISCARDED + internal CV_DISCARDED iscarded; + internal uint fileid; // First FILEID if line number info present + internal uint linenum; // First line number + internal byte[] data; // Original record(s) with invalid indices + }; + + // + // V7 line number data types + // + + internal enum DEBUG_S_SUBSECTION_TYPE : uint { + DEBUG_S_IGNORE=0x80000000, // if this bit is set in a subsection type then ignore the subsection contents + + DEBUG_S_SYMBOLS=0xf1, + DEBUG_S_LINES=0xf2, + DEBUG_S_STRINGTABLE=0xf3, + DEBUG_S_FILECHKSMS=0xf4, + DEBUG_S_FRAMEDATA=0xf5, + }; + + // + // Line flags (data present) + // + internal enum CV_LINE_SUBSECTION_FLAGS : ushort { + CV_LINES_HAVE_COLUMNS=0x0001, + } + + internal struct CV_LineSection { + internal uint off; + internal ushort sec; + internal ushort flags; + internal uint cod; + } + + internal struct CV_SourceFile { + internal uint index; // Index to file in checksum section. + internal uint count; // Number of CV_Line records. + internal uint linsiz; // Size of CV_Line recods. + } + + [Flags] + internal enum CV_Line_Flags : uint { + linenumStart=0x00ffffff, // line where statement/expression starts + deltaLineEnd=0x7f000000, // delta to line where statement ends (optional) + fStatement=0x80000000, // true if a statement linenumber, else an expression line num + }; + + internal struct CV_Line { + internal uint offset; // Offset to start of code bytes for line number + internal uint flags; // (CV_Line_Flags) + }; + + internal struct CV_Column { + internal ushort offColumnStart; + internal ushort offColumnEnd; + }; + + // File information + + internal enum CV_FILE_CHECKSUM_TYPE : byte { + None=0, + MD5=1, + }; + + internal struct CV_FileCheckSum { + internal uint name; // Index of name in name table. + internal byte len; // Hash length + internal byte type; // Hash type + } + + [Flags] + internal enum FRAMEDATA_FLAGS : uint { + fHasSEH=0x00000001, + fHasEH=0x00000002, + fIsFunctionStart=0x00000004, + }; + + internal struct FrameData { + internal uint ulRvaStart; + internal uint cbBlock; + internal uint cbLocals; + internal uint cbParams; + internal uint cbStkMax; + internal uint frameFunc; + internal ushort cbProlog; + internal ushort cbSavedRegs; + internal uint flags; // (FRAMEDATA_FLAGS) + }; + + internal struct XFixupData { + internal ushort wType; + internal ushort wExtra; + internal uint rva; + internal uint rvaTarget; + }; + + internal enum DEBUG_S_SUBSECTION { + SYMBOLS=0xF1, + LINES=0xF2, + STRINGTABLE=0xF3, + FILECHKSMS=0xF4, + FRAMEDATA=0xF5, + } +} \ No newline at end of file diff --git a/symbols/pdb/Microsoft.Cci.Pdb/DataStream.cs b/symbols/pdb/Microsoft.Cci.Pdb/DataStream.cs new file mode 100644 index 000000000..99929d980 --- /dev/null +++ b/symbols/pdb/Microsoft.Cci.Pdb/DataStream.cs @@ -0,0 +1,146 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.IO; + +namespace Microsoft.Cci.Pdb { + internal class DataStream { + internal DataStream() { + this.contentSize = 0; + this.pages = null; + } + + internal DataStream(int contentSize, BitAccess bits, int count) { + this.contentSize = contentSize; + if (count > 0) { + this.pages = new int[count]; + bits.ReadInt32(this.pages); + } + } + + internal void Read(PdbReader reader, BitAccess bits) { + bits.MinCapacity(contentSize); + Read(reader, 0, bits.Buffer, 0, contentSize); + } + + internal void Read(PdbReader reader, int position, + byte[] bytes, int offset, int data) { + if (position + data > contentSize) { + throw new PdbException("DataStream can't read off end of stream. " + + "(pos={0},siz={1})", + position, data); + } + if (position == contentSize) { + return; + } + + int left = data; + int page = position / reader.pageSize; + int rema = position % reader.pageSize; + + // First get remained of first page. + if (rema != 0) { + int todo = reader.pageSize - rema; + if (todo > left) { + todo = left; + } + + reader.Seek(pages[page], rema); + reader.Read(bytes, offset, todo); + + offset += todo; + left -= todo; + page++; + } + + // Now get the remaining pages. + while (left > 0) { + int todo = reader.pageSize; + if (todo > left) { + todo = left; + } + + reader.Seek(pages[page], 0); + reader.Read(bytes, offset, todo); + + offset += todo; + left -= todo; + page++; + } + } + + internal void Write(PdbWriter writer, byte[] bytes) { + Write(writer, bytes, bytes.Length); + } + + internal void Write(PdbWriter writer, byte[] bytes, int data) { + if (bytes == null || data == 0) { + return; + } + + int left = data; + int used = 0; + int rema = contentSize % writer.pageSize; + if (rema != 0) { + int todo = writer.pageSize - rema; + if (todo > left) { + todo = left; + } + + int lastPage = pages[pages.Length - 1]; + writer.Seek(lastPage, rema); + writer.Write(bytes, used, todo); + used += todo; + left -= todo; + } + + if (left > 0) { + int count = (left + writer.pageSize - 1) / writer.pageSize; + int page0 = writer.AllocatePages(count); + + writer.Seek(page0, 0); + writer.Write(bytes, used, left); + + AddPages(page0, count); + } + + contentSize += data; + } + + private void AddPages(int page0, int count) { + if (pages == null) { + pages = new int[count]; + for (int i = 0; i < count; i++) { + pages[i] = page0 + i; + } + } else { + int[] old = pages; + int used = old.Length; + + pages = new int[used + count]; + Array.Copy(old, pages, used); + for (int i = 0; i < count; i++) { + pages[used + i] = page0 + i; + } + } + } + + internal int Pages { + get { return pages == null ? 0 : pages.Length; } + } + + internal int Length { + get { return contentSize; } + } + + internal int GetPage(int index) { + return pages[index]; + } + + internal int contentSize; + internal int[] pages; + } +} diff --git a/symbols/pdb/Microsoft.Cci.Pdb/DbiDbgHdr.cs b/symbols/pdb/Microsoft.Cci.Pdb/DbiDbgHdr.cs new file mode 100644 index 000000000..b6159ab7a --- /dev/null +++ b/symbols/pdb/Microsoft.Cci.Pdb/DbiDbgHdr.cs @@ -0,0 +1,36 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; + +namespace Microsoft.Cci.Pdb { + internal struct DbiDbgHdr { + internal DbiDbgHdr(BitAccess bits) { + bits.ReadUInt16(out snFPO); + bits.ReadUInt16(out snException); + bits.ReadUInt16(out snFixup); + bits.ReadUInt16(out snOmapToSrc); + bits.ReadUInt16(out snOmapFromSrc); + bits.ReadUInt16(out snSectionHdr); + bits.ReadUInt16(out snTokenRidMap); + bits.ReadUInt16(out snXdata); + bits.ReadUInt16(out snPdata); + bits.ReadUInt16(out snNewFPO); + bits.ReadUInt16(out snSectionHdrOrig); + } + + internal ushort snFPO; // 0..1 + internal ushort snException; // 2..3 (deprecated) + internal ushort snFixup; // 4..5 + internal ushort snOmapToSrc; // 6..7 + internal ushort snOmapFromSrc; // 8..9 + internal ushort snSectionHdr; // 10..11 + internal ushort snTokenRidMap; // 12..13 + internal ushort snXdata; // 14..15 + internal ushort snPdata; // 16..17 + internal ushort snNewFPO; // 18..19 + internal ushort snSectionHdrOrig; // 20..21 + } +} diff --git a/symbols/pdb/Microsoft.Cci.Pdb/DbiHeader.cs b/symbols/pdb/Microsoft.Cci.Pdb/DbiHeader.cs new file mode 100644 index 000000000..29fb9fd9f --- /dev/null +++ b/symbols/pdb/Microsoft.Cci.Pdb/DbiHeader.cs @@ -0,0 +1,54 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; + +namespace Microsoft.Cci.Pdb { + internal struct DbiHeader { + internal DbiHeader(BitAccess bits) { + bits.ReadInt32(out sig); + bits.ReadInt32(out ver); + bits.ReadInt32(out age); + bits.ReadInt16(out gssymStream); + bits.ReadUInt16(out vers); + bits.ReadInt16(out pssymStream); + bits.ReadUInt16(out pdbver); + bits.ReadInt16(out symrecStream); + bits.ReadUInt16(out pdbver2); + bits.ReadInt32(out gpmodiSize); + bits.ReadInt32(out secconSize); + bits.ReadInt32(out secmapSize); + bits.ReadInt32(out filinfSize); + bits.ReadInt32(out tsmapSize); + bits.ReadInt32(out mfcIndex); + bits.ReadInt32(out dbghdrSize); + bits.ReadInt32(out ecinfoSize); + bits.ReadUInt16(out flags); + bits.ReadUInt16(out machine); + bits.ReadInt32(out reserved); + } + + internal int sig; // 0..3 + internal int ver; // 4..7 + internal int age; // 8..11 + internal short gssymStream; // 12..13 + internal ushort vers; // 14..15 + internal short pssymStream; // 16..17 + internal ushort pdbver; // 18..19 + internal short symrecStream; // 20..21 + internal ushort pdbver2; // 22..23 + internal int gpmodiSize; // 24..27 + internal int secconSize; // 28..31 + internal int secmapSize; // 32..35 + internal int filinfSize; // 36..39 + internal int tsmapSize; // 40..43 + internal int mfcIndex; // 44..47 + internal int dbghdrSize; // 48..51 + internal int ecinfoSize; // 52..55 + internal ushort flags; // 56..57 + internal ushort machine; // 58..59 + internal int reserved; // 60..63 + } +} diff --git a/symbols/pdb/Microsoft.Cci.Pdb/DbiModuleInfo.cs b/symbols/pdb/Microsoft.Cci.Pdb/DbiModuleInfo.cs new file mode 100644 index 000000000..a9a5b2ab2 --- /dev/null +++ b/symbols/pdb/Microsoft.Cci.Pdb/DbiModuleInfo.cs @@ -0,0 +1,52 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; + +namespace Microsoft.Cci.Pdb { + internal class DbiModuleInfo { + internal DbiModuleInfo(BitAccess bits, bool readStrings) { + bits.ReadInt32(out opened); + section = new DbiSecCon(bits); + bits.ReadUInt16(out flags); + bits.ReadInt16(out stream); + bits.ReadInt32(out cbSyms); + bits.ReadInt32(out cbOldLines); + bits.ReadInt32(out cbLines); + bits.ReadInt16(out files); + bits.ReadInt16(out pad1); + bits.ReadUInt32(out offsets); + bits.ReadInt32(out niSource); + bits.ReadInt32(out niCompiler); + if (readStrings) { + bits.ReadCString(out moduleName); + bits.ReadCString(out objectName); + } else { + bits.SkipCString(out moduleName); + bits.SkipCString(out objectName); + } + bits.Align(4); + //if (opened != 0 || pad1 != 0) { + // throw new PdbException("Invalid DBI module. "+ + // "(opened={0}, pad={1})", opened, pad1); + //} + } + + internal int opened; // 0..3 + internal DbiSecCon section; // 4..31 + internal ushort flags; // 32..33 + internal short stream; // 34..35 + internal int cbSyms; // 36..39 + internal int cbOldLines; // 40..43 + internal int cbLines; // 44..57 + internal short files; // 48..49 + internal short pad1; // 50..51 + internal uint offsets; + internal int niSource; + internal int niCompiler; + internal string moduleName; + internal string objectName; + } +} diff --git a/symbols/pdb/Microsoft.Cci.Pdb/DbiSecCon.cs b/symbols/pdb/Microsoft.Cci.Pdb/DbiSecCon.cs new file mode 100644 index 000000000..1e2b60d78 --- /dev/null +++ b/symbols/pdb/Microsoft.Cci.Pdb/DbiSecCon.cs @@ -0,0 +1,37 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; + +namespace Microsoft.Cci.Pdb { + internal struct DbiSecCon { + internal DbiSecCon(BitAccess bits) { + bits.ReadInt16(out section); + bits.ReadInt16(out pad1); + bits.ReadInt32(out offset); + bits.ReadInt32(out size); + bits.ReadUInt32(out flags); + bits.ReadInt16(out module); + bits.ReadInt16(out pad2); + bits.ReadUInt32(out dataCrc); + bits.ReadUInt32(out relocCrc); + //if (pad1 != 0 || pad2 != 0) { + // throw new PdbException("Invalid DBI section. "+ + // "(pad1={0}, pad2={1})", + // pad1, pad2); + //} + } + + internal short section; // 0..1 + internal short pad1; // 2..3 + internal int offset; // 4..7 + internal int size; // 8..11 + internal uint flags; // 12..15 + internal short module; // 16..17 + internal short pad2; // 18..19 + internal uint dataCrc; // 20..23 + internal uint relocCrc; // 24..27 + } +} diff --git a/symbols/pdb/Microsoft.Cci.Pdb/IntHashTable.cs b/symbols/pdb/Microsoft.Cci.Pdb/IntHashTable.cs new file mode 100644 index 000000000..a092b1ca0 --- /dev/null +++ b/symbols/pdb/Microsoft.Cci.Pdb/IntHashTable.cs @@ -0,0 +1,579 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.Collections; + +namespace Microsoft.Cci.Pdb { + // The IntHashTable class represents a dictionary of associated keys and + // values with constant lookup time. + // + // Objects used as keys in a hashtable must implement the GetHashCode + // and Equals methods (or they can rely on the default implementations + // inherited from Object if key equality is simply reference + // equality). Furthermore, the GetHashCode and Equals methods of + // a key object must produce the same results given the same parameters + // for the entire time the key is present in the hashtable. In practical + // terms, this means that key objects should be immutable, at least for + // the time they are used as keys in a hashtable. + // + // When entries are added to a hashtable, they are placed into + // buckets based on the hashcode of their keys. Subsequent lookups of + // keys will use the hashcode of the keys to only search a particular + // bucket, thus substantially reducing the number of key comparisons + // required to find an entry. A hashtable's maximum load factor, which + // can be specified when the hashtable is instantiated, determines the + // maximum ratio of hashtable entries to hashtable buckets. Smaller load + // factors cause faster average lookup times at the cost of increased + // memory consumption. The default maximum load factor of 1.0 generally + // provides the best balance between speed and size. As entries are added + // to a hashtable, the hashtable's actual load factor increases, and when + // the actual load factor reaches the maximum load factor value, the + // number of buckets in the hashtable is automatically increased by + // approximately a factor of two (to be precise, the number of hashtable + // buckets is increased to the smallest prime number that is larger than + // twice the current number of hashtable buckets). + // + // Each object provides their own hash function, accessed by calling + // GetHashCode(). However, one can write their own object + // implementing IHashCodeProvider and pass it to a constructor on + // the IntHashTable. That hash function would be used for all objects in + // the table. + // + // This IntHashTable is implemented to support multiple concurrent readers + // and one concurrent writer without using any synchronization primitives. + // All read methods essentially must protect themselves from a resize + // occuring while they are running. This was done by enforcing an + // ordering on inserts & removes, as well as removing some member variables + // and special casing the expand code to work in a temporary array instead + // of the live bucket array. All inserts must set a bucket's value and + // key before setting the hash code & collision field. + // + // By Brian Grunkemeyer, algorithm by Patrick Dussud. + // Version 1.30 2/20/2000 + //| + internal class IntHashTable : IEnumerable { + /* + Implementation Notes: + + This IntHashTable uses double hashing. There are hashsize buckets in + the table, and each bucket can contain 0 or 1 element. We a bit to + mark whether there's been a collision when we inserted multiple + elements (ie, an inserted item was hashed at least a second time and + we probed this bucket, but it was already in use). Using the + collision bit, we can terminate lookups & removes for elements that + aren't in the hash table more quickly. We steal the most + significant bit from the hash code to store the collision bit. + + Our hash function is of the following form: + + h(key, n) = h1(key) + n*h2(key) + + where n is the number of times we've hit a collided bucket and + rehashed (on this particular lookup). Here are our hash functions: + + h1(key) = GetHash(key); // default implementation calls key.GetHashCode(); + h2(key) = 1 + (((h1(key) >> 5) + 1) % (hashsize - 1)); + + The h1 can return any number. h2 must return a number between 1 and + hashsize - 1 that is relatively prime to hashsize (not a problem if + hashsize is prime). (Knuth's Art of Computer Programming, Vol. 3, + p. 528-9) + + If this is true, then we are guaranteed to visit every bucket in + exactly hashsize probes, since the least common multiple of hashsize + and h2(key) will be hashsize * h2(key). (This is the first number + where adding h2 to h1 mod hashsize will be 0 and we will search the + same bucket twice). + + We previously used a different h2(key, n) that was not constant. + That is a horrifically bad idea, unless you can prove that series + will never produce any identical numbers that overlap when you mod + them by hashsize, for all subranges from i to i+hashsize, for all i. + It's not worth investigating, since there was no clear benefit from + using that hash function, and it was broken. + + For efficiency reasons, we've implemented this by storing h1 and h2 + in a temporary, and setting a variable called seed equal to h1. We + do a probe, and if we collided, we simply add h2 to seed each time + through the loop. + + A good test for h2() is to subclass IntHashTable, provide your own + implementation of GetHash() that returns a constant, then add many + items to the hash table. Make sure Count equals the number of items + you inserted. + + -- Brian Grunkemeyer, 10/28/1999 + */ + + // A typical resize algorithm would pick the smallest prime number in this array + // that is larger than twice the previous capacity. + // Suppose our Hashtable currently has capacity x and enough elements are added + // such that a resize needs to occur. Resizing first computes 2x then finds the + // first prime in the table greater than 2x, i.e. if primes are ordered + // p_1, p_2, …, p_i,…, it finds p_n such that p_n-1 < 2x < p_n. + // Doubling is important for preserving the asymptotic complexity of the + // hashtable operations such as add. Having a prime guarantees that double + // hashing does not lead to infinite loops. IE, your hash function will be + // h1(key) + i*h2(key), 0 <= i < size. h2 and the size must be relatively prime. + private static readonly int[] primes = { + 3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, 761, 919, + 1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591, + 17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363, 156437, + 187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, 968897, 1162687, 1395263, + 1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559, 5999471, 7199369}; + + private int GetPrime(int minSize) { + if (minSize < 0) { + throw new ArgumentException("Arg_HTCapacityOverflow"); + } + for (int i = 0; i < primes.Length; i++) { + int size = primes[i]; + if (size >= minSize) { + return size; + } + } + throw new ArgumentException("Arg_HTCapacityOverflow"); + } + + // Deleted entries have their key set to buckets + + // The hash table data. + // This cannot be serialised + private struct bucket { + internal int key; + internal int hash_coll; // Store hash code; sign bit means there was a collision. + internal Object val; + } + + private bucket[] buckets; + + // The total number of entries in the hash table. + private int count; + + // The total number of collision bits set in the hashtable + private int occupancy; + + private int loadsize; + private int loadFactorPerc; // 100 = 1.0 + + private int version; + + // Constructs a new hashtable. The hashtable is created with an initial + // capacity of zero and a load factor of 1.0. + //| + internal IntHashTable() + : this(0, 100) { + } + + // Constructs a new hashtable with the given initial capacity and a load + // factor of 1.0. The capacity argument serves as an indication of + // the number of entries the hashtable will contain. When this number (or + // an approximation) is known, specifying it in the constructor can + // eliminate a number of resizing operations that would otherwise be + // performed when elements are added to the hashtable. + // + //| + internal IntHashTable(int capacity) + : this(capacity, 100) { + } + + // Constructs a new hashtable with the given initial capacity and load + // factor. The capacity argument serves as an indication of the + // number of entries the hashtable will contain. When this number (or an + // approximation) is known, specifying it in the constructor can eliminate + // a number of resizing operations that would otherwise be performed when + // elements are added to the hashtable. The loadFactorPerc argument + // indicates the maximum ratio of hashtable entries to hashtable buckets. + // Smaller load factors cause faster average lookup times at the cost of + // increased memory consumption. A load factor of 1.0 generally provides + // the best balance between speed and size. + // + //| + internal IntHashTable(int capacity, int loadFactorPerc) { + if (capacity < 0) + throw new ArgumentOutOfRangeException("capacity", "ArgumentOutOfRange_NeedNonNegNum"); + if (!(loadFactorPerc >= 10 && loadFactorPerc <= 100)) + throw new ArgumentOutOfRangeException("loadFactorPerc", String.Format("ArgumentOutOfRange_IntHashTableLoadFactor", 10, 100)); + + // Based on perf work, .72 is the optimal load factor for this table. + this.loadFactorPerc = (loadFactorPerc * 72) / 100; + + int hashsize = GetPrime((int)(capacity / this.loadFactorPerc)); + buckets = new bucket[hashsize]; + + loadsize = (int)(this.loadFactorPerc * hashsize) / 100; + if (loadsize >= hashsize) + loadsize = hashsize-1; + } + + // Computes the hash function: H(key, i) = h1(key) + i*h2(key, hashSize). + // The out parameter seed is h1(key), while the out parameter + // incr is h2(key, hashSize). Callers of this function should + // add incr each time through a loop. + private uint InitHash(int key, int hashsize, out uint seed, out uint incr) { + // Hashcode must be positive. Also, we must not use the sign bit, since + // that is used for the collision bit. + uint hashcode = (uint)key & 0x7FFFFFFF; + seed = (uint)hashcode; + // Restriction: incr MUST be between 1 and hashsize - 1, inclusive for + // the modular arithmetic to work correctly. This guarantees you'll + // visit every bucket in the table exactly once within hashsize + // iterations. Violate this and it'll cause obscure bugs forever. + // If you change this calculation for h2(key), update putEntry too! + incr = (uint)(1 + (((seed >> 5) + 1) % ((uint)hashsize - 1))); + return hashcode; + } + + // Adds an entry with the given key and value to this hashtable. An + // ArgumentException is thrown if the key is null or if the key is already + // present in the hashtable. + // + //| + internal void Add(int key, Object value) { + Insert(key, value, true); + } + + // Removes all entries from this hashtable. + //| + internal void Clear() { + if (count == 0) + return; + + for (int i = 0; i < buckets.Length; i++) { + buckets[i].hash_coll = 0; + buckets[i].key = -1; + buckets[i].val = null; + } + + count = 0; + occupancy = 0; + } + + // Checks if this hashtable contains an entry with the given key. This is + // an O(1) operation. + // + //| + internal bool Contains(int key) { + if (key < 0) { + throw new ArgumentException("Argument_KeyLessThanZero"); + } + + uint seed; + uint incr; + // Take a snapshot of buckets, in case another thread resizes table + bucket[] lbuckets = buckets; + uint hashcode = InitHash(key, lbuckets.Length, out seed, out incr); + int ntry = 0; + + bucket b; + do { + int bucketNumber = (int)(seed % (uint)lbuckets.Length); + b = lbuckets[bucketNumber]; + if (b.val == null) { + return false; + } + if (((b.hash_coll & 0x7FFFFFFF) == hashcode) && b.key == key) { + return true; + } + seed += incr; + } while (b.hash_coll < 0 && ++ntry < lbuckets.Length); + return false; + } + + // Returns the value associated with the given key. If an entry with the + // given key is not found, the returned value is null. + // + //| + internal Object this[int key] { + get { + if (key < 0) { + throw new ArgumentException("Argument_KeyLessThanZero"); + } + uint seed; + uint incr; + // Take a snapshot of buckets, in case another thread does a resize + bucket[] lbuckets = buckets; + uint hashcode = InitHash(key, lbuckets.Length, out seed, out incr); + int ntry = 0; + + bucket b; + do { + int bucketNumber = (int)(seed % (uint)lbuckets.Length); + b = lbuckets[bucketNumber]; + if (b.val == null) { + return null; + } + if (((b.hash_coll & 0x7FFFFFFF) == hashcode) && key == b.key) { + return b.val; + } + seed += incr; + } while (b.hash_coll < 0 && ++ntry < lbuckets.Length); + return null; + } + set { + Insert(key, value, false); + } + } + + // Increases the bucket count of this hashtable. This method is called from + // the Insert method when the actual load factor of the hashtable reaches + // the upper limit specified when the hashtable was constructed. The number + // of buckets in the hashtable is increased to the smallest prime number + // that is larger than twice the current number of buckets, and the entries + // in the hashtable are redistributed into the new buckets using the cached + // hashcodes. + private void expand() { + rehash(GetPrime(1+buckets.Length*2)); + } + + // We occationally need to rehash the table to clean up the collision bits. + private void rehash() { + rehash(buckets.Length); + } + + private void rehash(int newsize) { + + // reset occupancy + occupancy=0; + + // Don't replace any internal state until we've finished adding to the + // new bucket[]. This serves two purposes: + // 1) Allow concurrent readers to see valid hashtable contents + // at all times + // 2) Protect against an OutOfMemoryException while allocating this + // new bucket[]. + bucket[] newBuckets = new bucket[newsize]; + + // rehash table into new buckets + int nb; + for (nb = 0; nb < buckets.Length; nb++) { + bucket oldb = buckets[nb]; + if (oldb.val != null) { + putEntry(newBuckets, oldb.key, oldb.val, oldb.hash_coll & 0x7FFFFFFF); + } + } + + // New bucket[] is good to go - replace buckets and other internal state. + version++; + buckets = newBuckets; + loadsize = (int)(loadFactorPerc * newsize) / 100; + + if (loadsize >= newsize) { + loadsize = newsize-1; + } + + return; + } + + // Returns an enumerator for this hashtable. + // If modifications made to the hashtable while an enumeration is + // in progress, the MoveNext and Current methods of the + // enumerator will throw an exception. + // + //| + IEnumerator IEnumerable.GetEnumerator() { + return new IntHashTableEnumerator(this); + } + + // Internal method to compare two keys. + // + // Inserts an entry into this hashtable. This method is called from the Set + // and Add methods. If the add parameter is true and the given key already + // exists in the hashtable, an exception is thrown. + private void Insert(int key, Object nvalue, bool add) { + if (key < 0) { + throw new ArgumentException("Argument_KeyLessThanZero"); + } + if (nvalue == null) { + throw new ArgumentNullException("nvalue", "ArgumentNull_Value"); + } + if (count >= loadsize) { + expand(); + } else if (occupancy > loadsize && count > 100) { + rehash(); + } + + uint seed; + uint incr; + // Assume we only have one thread writing concurrently. Modify + // buckets to contain new data, as long as we insert in the right order. + uint hashcode = InitHash(key, buckets.Length, out seed, out incr); + int ntry = 0; + int emptySlotNumber = -1; // We use the empty slot number to cache the first empty slot. We chose to reuse slots + // create by remove that have the collision bit set over using up new slots. + + do { + int bucketNumber = (int)(seed % (uint)buckets.Length); + + // Set emptySlot number to current bucket if it is the first available bucket that we have seen + // that once contained an entry and also has had a collision. + // We need to search this entire collision chain because we have to ensure that there are no + // duplicate entries in the table. + + // Insert the key/value pair into this bucket if this bucket is empty and has never contained an entry + // OR + // This bucket once contained an entry but there has never been a collision + if (buckets[bucketNumber].val == null) { + // If we have found an available bucket that has never had a collision, but we've seen an available + // bucket in the past that has the collision bit set, use the previous bucket instead + if (emptySlotNumber != -1) { // Reuse slot + bucketNumber = emptySlotNumber; + } + + // We pretty much have to insert in this order. Don't set hash + // code until the value & key are set appropriately. + buckets[bucketNumber].val = nvalue; + buckets[bucketNumber].key = key; + buckets[bucketNumber].hash_coll |= (int)hashcode; + count++; + version++; + return; + } + + // The current bucket is in use + // OR + // it is available, but has had the collision bit set and we have already found an available bucket + if (((buckets[bucketNumber].hash_coll & 0x7FFFFFFF) == hashcode) && + key == buckets[bucketNumber].key) { + if (add) { + throw new ArgumentException("Argument_AddingDuplicate__" + buckets[bucketNumber].key); + } + buckets[bucketNumber].val = nvalue; + version++; + return; + } + + // The current bucket is full, and we have therefore collided. We need to set the collision bit + // UNLESS + // we have remembered an available slot previously. + if (emptySlotNumber == -1) {// We don't need to set the collision bit here since we already have an empty slot + if (buckets[bucketNumber].hash_coll >= 0) { + buckets[bucketNumber].hash_coll |= unchecked((int)0x80000000); + occupancy++; + } + } + seed += incr; + } while (++ntry < buckets.Length); + + // This code is here if and only if there were no buckets without a collision bit set in the entire table + if (emptySlotNumber != -1) { + // We pretty much have to insert in this order. Don't set hash + // code until the value & key are set appropriately. + buckets[emptySlotNumber].val = nvalue; + buckets[emptySlotNumber].key = key; + buckets[emptySlotNumber].hash_coll |= (int)hashcode; + count++; + version++; + return; + + } + + // If you see this assert, make sure load factor & count are reasonable. + // Then verify that our double hash function (h2, described at top of file) + // meets the requirements described above. You should never see this assert. + throw new InvalidOperationException("InvalidOperation_HashInsertFailed"); + } + + private void putEntry(bucket[] newBuckets, int key, Object nvalue, int hashcode) { + uint seed = (uint)hashcode; + uint incr = (uint)(1 + (((seed >> 5) + 1) % ((uint)newBuckets.Length - 1))); + + do { + int bucketNumber = (int)(seed % (uint)newBuckets.Length); + + if ((newBuckets[bucketNumber].val == null)) { + newBuckets[bucketNumber].val = nvalue; + newBuckets[bucketNumber].key = key; + newBuckets[bucketNumber].hash_coll |= hashcode; + return; + } + + if (newBuckets[bucketNumber].hash_coll >= 0) { + newBuckets[bucketNumber].hash_coll |= unchecked((int)0x80000000); + occupancy++; + } + seed += incr; + } while (true); + } + + // Returns the number of associations in this hashtable. + // + //| + internal int Count { + get { return count; } + } + + // Implements an enumerator for a hashtable. The enumerator uses the + // internal version number of the hashtabke to ensure that no modifications + // are made to the hashtable while an enumeration is in progress. + private class IntHashTableEnumerator : IEnumerator { + private IntHashTable hashtable; + private int bucket; + private int version; + private bool current; + private int currentKey; + private Object currentValue; + + internal IntHashTableEnumerator(IntHashTable hashtable) { + this.hashtable = hashtable; + bucket = hashtable.buckets.Length; + version = hashtable.version; + current = false; + } + + public bool MoveNext() { + if (version != hashtable.version) + throw new InvalidOperationException("InvalidOperation_EnumFailedVersion"); + while (bucket > 0) { + bucket--; + Object val = hashtable.buckets[bucket].val; + if (val != null) { + currentKey = hashtable.buckets[bucket].key; + currentValue = val; + current = true; + return true; + } + } + current = false; + return false; + } + + internal int Key { + get { + if (current == false) + throw new InvalidOperationException("InvalidOperation_EnumOpCantHappen"); + return currentKey; + } + } + + public Object Current { + get { + if (current == false) + throw new InvalidOperationException("InvalidOperation_EnumOpCantHappen"); + return currentValue; + } + } + + public Object Value { + get { + if (version != hashtable.version) + throw new InvalidOperationException("InvalidOperation_EnumFailedVersion"); + if (current == false) + throw new InvalidOperationException("InvalidOperation_EnumOpCantHappen"); + return currentValue; + } + } + + public void Reset() { + if (version != hashtable.version) throw new InvalidOperationException("InvalidOperation_EnumFailedVersion"); + current = false; + bucket = hashtable.buckets.Length; + currentKey = -1; + currentValue = null; + } + } + } +} diff --git a/symbols/pdb/Microsoft.Cci.Pdb/Interfaces.cs b/symbols/pdb/Microsoft.Cci.Pdb/Interfaces.cs new file mode 100644 index 000000000..82561fbcc --- /dev/null +++ b/symbols/pdb/Microsoft.Cci.Pdb/Interfaces.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; + +namespace Microsoft.Cci { + + /// + /// A range of CLR IL operations that comprise a lexical scope, specified as an IL offset and a length. + /// + public interface ILocalScope { + /// + /// The offset of the first operation in the scope. + /// + uint Offset { get; } + + /// + /// The length of the scope. Offset+Length equals the offset of the first operation outside the scope, or equals the method body length. + /// + uint Length { get; } + } + + /// + /// A description of the lexical scope in which a namespace type has been nested. This scope is tied to a particular + /// method body, so that partial types can be accommodated. + /// + public interface INamespaceScope { + + /// + /// Zero or more used namespaces. These correspond to using clauses in C#. + /// + IEnumerable UsedNamespaces { get; } + + } + + + /// + /// A namespace that is used (imported) inside a namespace scope. + /// + public interface IUsedNamespace { + /// + /// An alias for a namespace. For example the "x" of "using x = y.z;" in C#. Empty if no alias is present. + /// + IName Alias { get; } + + /// + /// The name of a namepace that has been aliased. For example the "y.z" of "using x = y.z;" or "using y.z" in C#. + /// + IName NamespaceName { get; } + } + + /// + /// The name of an entity. Typically name instances come from a common pool. Within the pool no two distinct instances will have the same Value or UniqueKey. + /// + public interface IName { + /// + /// An integer that is unique within the pool from which the name instance has been allocated. Useful as a hashtable key. + /// + int UniqueKey { + get; + //^ ensures result > 0; + } + + /// + /// An integer that is unique within the pool from which the name instance has been allocated. Useful as a hashtable key. + /// All name instances in the pool that have the same string value when ignoring the case of the characters in the string + /// will have the same key value. + /// + int UniqueKeyIgnoringCase { + get; + //^ ensures result > 0; + } + + /// + /// The string value corresponding to this name. + /// + string Value { get; } + } +} \ No newline at end of file diff --git a/symbols/pdb/Microsoft.Cci.Pdb/LICENSE b/symbols/pdb/Microsoft.Cci.Pdb/LICENSE new file mode 100755 index 000000000..7bfc997e5 --- /dev/null +++ b/symbols/pdb/Microsoft.Cci.Pdb/LICENSE @@ -0,0 +1,22 @@ +Microsoft Public License (Ms-PL) + +This license governs use of the accompanying software. If you use the software, you +accept this license. If you do not accept the license, do not use the software. + +1. Definitions +The terms "reproduce," "reproduction," "derivative works," and "distribution" have the +same meaning here as under U.S. copyright law. +A "contribution" is the original software, or any additions or changes to the software. +A "contributor" is any person that distributes its contribution under this license. +"Licensed patents" are a contributor's patent claims that read directly on its contribution. + +2. Grant of Rights +(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create. +(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software. + +3. Conditions and Limitations +(A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks. +(B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically. +(C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software. +(D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license. +(E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement. diff --git a/symbols/pdb/Microsoft.Cci.Pdb/MsfDirectory.cs b/symbols/pdb/Microsoft.Cci.Pdb/MsfDirectory.cs new file mode 100644 index 000000000..3a7910d7d --- /dev/null +++ b/symbols/pdb/Microsoft.Cci.Pdb/MsfDirectory.cs @@ -0,0 +1,45 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; + +namespace Microsoft.Cci.Pdb { + internal class MsfDirectory { + internal MsfDirectory(PdbReader reader, PdbFileHeader head, BitAccess bits) { + bits.MinCapacity(head.directorySize); + int pages = reader.PagesFromSize(head.directorySize); + + // 0..n in page of directory pages. + reader.Seek(head.directoryRoot, 0); + bits.FillBuffer(reader.reader, pages * 4); + + DataStream stream = new DataStream(head.directorySize, bits, pages); + bits.MinCapacity(head.directorySize); + stream.Read(reader, bits); + + // 0..3 in directory pages + int count; + bits.ReadInt32(out count); + + // 4..n + int[] sizes = new int[count]; + bits.ReadInt32(sizes); + + // n..m + streams = new DataStream[count]; + for (int i = 0; i < count; i++) { + if (sizes[i] <= 0) { + streams[i] = new DataStream(); + } else { + streams[i] = new DataStream(sizes[i], bits, + reader.PagesFromSize(sizes[i])); + } + } + } + + internal DataStream[] streams; + } + +} diff --git a/symbols/pdb/Microsoft.Cci.Pdb/PdbConstant.cs b/symbols/pdb/Microsoft.Cci.Pdb/PdbConstant.cs new file mode 100644 index 000000000..1f1aec1fd --- /dev/null +++ b/symbols/pdb/Microsoft.Cci.Pdb/PdbConstant.cs @@ -0,0 +1,79 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.Runtime.InteropServices; + +namespace Microsoft.Cci.Pdb { + internal class PdbConstant { + internal string name; + internal uint token; + internal object value; + + internal PdbConstant(BitAccess bits) { + bits.ReadUInt32(out this.token); + byte tag1; + bits.ReadUInt8(out tag1); + byte tag2; + bits.ReadUInt8(out tag2); + if (tag2 == 0) { + this.value = tag1; + } else if (tag2 == 0x80) { + switch (tag1) { + case 0x01: //short + short s; + bits.ReadInt16(out s); + this.value = s; + break; + case 0x02: //ushort + ushort us; + bits.ReadUInt16(out us); + this.value = us; + break; + case 0x03: //int + int i; + bits.ReadInt32(out i); + this.value = i; + break; + case 0x04: //uint + uint ui; + bits.ReadUInt32(out ui); + this.value = ui; + break; + case 0x05: //float + this.value = bits.ReadFloat(); + break; + case 0x06: //double + this.value = bits.ReadDouble(); + break; + case 0x09: //long + long sl; + bits.ReadInt64(out sl); + this.value = sl; + break; + case 0x0a: //ulong + ulong ul; + bits.ReadUInt64(out ul); + this.value = ul; + break; + case 0x10: //string + string str; + bits.ReadBString(out str); + this.value = str; + break; + case 0x19: //decimal + this.value = bits.ReadDecimal(); + break; + default: + //TODO: error + break; + } + } else { + //TODO: error + } + bits.ReadCString(out name); + } + } +} diff --git a/symbols/pdb/Microsoft.Cci.Pdb/PdbDebugException.cs b/symbols/pdb/Microsoft.Cci.Pdb/PdbDebugException.cs new file mode 100644 index 000000000..515dc37c7 --- /dev/null +++ b/symbols/pdb/Microsoft.Cci.Pdb/PdbDebugException.cs @@ -0,0 +1,15 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.IO; + +namespace Microsoft.Cci.Pdb { + internal class PdbDebugException : IOException { + internal PdbDebugException(String format, params object[] args) + : base(String.Format(format, args)) { + } + } +} diff --git a/symbols/pdb/Microsoft.Cci.Pdb/PdbException.cs b/symbols/pdb/Microsoft.Cci.Pdb/PdbException.cs new file mode 100644 index 000000000..0dd7f9384 --- /dev/null +++ b/symbols/pdb/Microsoft.Cci.Pdb/PdbException.cs @@ -0,0 +1,15 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.IO; + +namespace Microsoft.Cci.Pdb { + internal class PdbException : IOException { + internal PdbException(String format, params object[] args) + : base(String.Format(format, args)) { + } + } +} diff --git a/symbols/pdb/Microsoft.Cci.Pdb/PdbFile.cs b/symbols/pdb/Microsoft.Cci.Pdb/PdbFile.cs new file mode 100644 index 000000000..d6d493ccf --- /dev/null +++ b/symbols/pdb/Microsoft.Cci.Pdb/PdbFile.cs @@ -0,0 +1,421 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Diagnostics.SymbolStore; + +namespace Microsoft.Cci.Pdb { + internal class PdbFile { + private PdbFile() // This class can't be instantiated. + { + } + + static void LoadGuidStream(BitAccess bits, out Guid doctype, out Guid language, out Guid vendor) { + bits.ReadGuid(out language); + bits.ReadGuid(out vendor); + bits.ReadGuid(out doctype); + } + + static Dictionary LoadNameIndex(BitAccess bits, out int age, out Guid guid) { + Dictionary result = new Dictionary(); + int ver; + int sig; + bits.ReadInt32(out ver); // 0..3 Version + bits.ReadInt32(out sig); // 4..7 Signature + bits.ReadInt32(out age); // 8..11 Age + bits.ReadGuid(out guid); // 12..27 GUID + + if (ver != 20000404) { + throw new PdbDebugException("Unsupported PDB Stream version {0}", ver); + } + + // Read string buffer. + int buf; + bits.ReadInt32(out buf); // 28..31 Bytes of Strings + + int beg = bits.Position; + int nxt = bits.Position + buf; + + bits.Position = nxt; + + // Read map index. + int cnt; // n+0..3 hash size. + int max; // n+4..7 maximum ni. + + bits.ReadInt32(out cnt); + bits.ReadInt32(out max); + + BitSet present = new BitSet(bits); + BitSet deleted = new BitSet(bits); + if (!deleted.IsEmpty) { + throw new PdbDebugException("Unsupported PDB deleted bitset is not empty."); + } + + int j = 0; + for (int i = 0; i < max; i++) { + if (present.IsSet(i)) { + int ns; + int ni; + bits.ReadInt32(out ns); + bits.ReadInt32(out ni); + + string name; + int saved = bits.Position; + bits.Position = beg + ns; + bits.ReadCString(out name); + bits.Position = saved; + + result.Add(name, ni); + j++; + } + } + if (j != cnt) { + throw new PdbDebugException("Count mismatch. ({0} != {1})", j, cnt); + } + return result; + } + + static IntHashTable LoadNameStream(BitAccess bits) { + IntHashTable ht = new IntHashTable(); + + uint sig; + int ver; + bits.ReadUInt32(out sig); // 0..3 Signature + bits.ReadInt32(out ver); // 4..7 Version + + // Read (or skip) string buffer. + int buf; + bits.ReadInt32(out buf); // 8..11 Bytes of Strings + + if (sig != 0xeffeeffe || ver != 1) { + throw new PdbDebugException("Unsupported Name Stream version. "+ + "(sig={0:x8}, ver={1})", + sig, ver); + } + int beg = bits.Position; + int nxt = bits.Position + buf; + bits.Position = nxt; + + // Read hash table. + int siz; + bits.ReadInt32(out siz); // n+0..3 Number of hash buckets. + nxt = bits.Position; + + for (int i = 0; i < siz; i++) { + int ni; + string name; + + bits.ReadInt32(out ni); + + if (ni != 0) { + int saved = bits.Position; + bits.Position = beg + ni; + bits.ReadCString(out name); + bits.Position = saved; + + ht.Add(ni, name); + } + } + bits.Position = nxt; + + return ht; + } + + private static PdbFunction match = new PdbFunction(); + + private static PdbFunction FindFunction(PdbFunction[] funcs, ushort sec, uint off) { + match.segment = sec; + match.address = off; + + int item = Array.BinarySearch(funcs, match, PdbFunction.byAddress); + if (item >= 0) { + return funcs[item]; + } + return null; + } + + static void LoadManagedLines(PdbFunction[] funcs, + IntHashTable names, + BitAccess bits, + MsfDirectory dir, + Dictionary nameIndex, + PdbReader reader, + uint limit) { + Array.Sort(funcs, PdbFunction.byAddress); + IntHashTable checks = new IntHashTable(); + + // Read the files first + int begin = bits.Position; + while (bits.Position < limit) { + int sig; + int siz; + bits.ReadInt32(out sig); + bits.ReadInt32(out siz); + int place = bits.Position; + int endSym = bits.Position + siz; + + switch ((DEBUG_S_SUBSECTION)sig) { + case DEBUG_S_SUBSECTION.FILECHKSMS: + while (bits.Position < endSym) { + CV_FileCheckSum chk; + + int ni = bits.Position - place; + bits.ReadUInt32(out chk.name); + bits.ReadUInt8(out chk.len); + bits.ReadUInt8(out chk.type); + + string name = (string)names[(int)chk.name]; + int guidStream; + Guid doctypeGuid = SymDocumentType.Text; + Guid languageGuid = SymLanguageType.CSharp; + Guid vendorGuid = SymLanguageVendor.Microsoft; + if (nameIndex.TryGetValue("/src/files/"+name, out guidStream)) { + var guidBits = new BitAccess(0x100); + dir.streams[guidStream].Read(reader, guidBits); + LoadGuidStream(guidBits, out doctypeGuid, out languageGuid, out vendorGuid); + } + + PdbSource src = new PdbSource((uint)ni, name, doctypeGuid, languageGuid, vendorGuid); + checks.Add(ni, src); + bits.Position += chk.len; + bits.Align(4); + } + bits.Position = endSym; + break; + + default: + bits.Position = endSym; + break; + } + } + + // Read the lines next. + bits.Position = begin; + while (bits.Position < limit) { + int sig; + int siz; + bits.ReadInt32(out sig); + bits.ReadInt32(out siz); + int endSym = bits.Position + siz; + + switch ((DEBUG_S_SUBSECTION)sig) { + case DEBUG_S_SUBSECTION.LINES: { + CV_LineSection sec; + + bits.ReadUInt32(out sec.off); + bits.ReadUInt16(out sec.sec); + bits.ReadUInt16(out sec.flags); + bits.ReadUInt32(out sec.cod); + PdbFunction func = FindFunction(funcs, sec.sec, sec.off); + if (func == null) break; + + // Count the line blocks. + int begSym = bits.Position; + int blocks = 0; + while (bits.Position < endSym) { + CV_SourceFile file; + bits.ReadUInt32(out file.index); + bits.ReadUInt32(out file.count); + bits.ReadUInt32(out file.linsiz); // Size of payload. + int linsiz = (int)file.count * (8 + ((sec.flags & 1) != 0 ? 4 : 0)); + bits.Position += linsiz; + blocks++; + } + + func.lines = new PdbLines[blocks]; + int block = 0; + + bits.Position = begSym; + while (bits.Position < endSym) { + CV_SourceFile file; + bits.ReadUInt32(out file.index); + bits.ReadUInt32(out file.count); + bits.ReadUInt32(out file.linsiz); // Size of payload. + + PdbSource src = (PdbSource)checks[(int)file.index]; + PdbLines tmp = new PdbLines(src, file.count); + func.lines[block++] = tmp; + PdbLine[] lines = tmp.lines; + + int plin = bits.Position; + int pcol = bits.Position + 8 * (int)file.count; + + for (int i = 0; i < file.count; i++) { + CV_Line line; + CV_Column column = new CV_Column(); + + bits.Position = plin + 8 * i; + bits.ReadUInt32(out line.offset); + bits.ReadUInt32(out line.flags); + + uint lineBegin = line.flags & (uint)CV_Line_Flags.linenumStart; + uint delta = (line.flags & (uint)CV_Line_Flags.deltaLineEnd) >> 24; + bool statement = ((line.flags & (uint)CV_Line_Flags.fStatement) == 0); + if ((sec.flags & 1) != 0) { + bits.Position = pcol + 4 * i; + bits.ReadUInt16(out column.offColumnStart); + bits.ReadUInt16(out column.offColumnEnd); + } + + lines[i] = new PdbLine(line.offset, + lineBegin, + column.offColumnStart, + lineBegin+delta, + column.offColumnEnd); + } + } + break; + } + } + bits.Position = endSym; + } + } + + static void LoadFuncsFromDbiModule(BitAccess bits, + DbiModuleInfo info, + IntHashTable names, + ArrayList funcList, + bool readStrings, + MsfDirectory dir, + Dictionary nameIndex, + PdbReader reader) { + PdbFunction[] funcs = null; + + bits.Position = 0; + int sig; + bits.ReadInt32(out sig); + if (sig != 4) { + throw new PdbDebugException("Invalid signature. (sig={0})", sig); + } + + bits.Position = 4; + // Console.WriteLine("{0}:", info.moduleName); + funcs = PdbFunction.LoadManagedFunctions(info.moduleName, + bits, (uint)info.cbSyms, + readStrings); + if (funcs != null) { + bits.Position = info.cbSyms + info.cbOldLines; + LoadManagedLines(funcs, names, bits, dir, nameIndex, reader, + (uint)(info.cbSyms + info.cbOldLines + info.cbLines)); + + for (int i = 0; i < funcs.Length; i++) { + funcList.Add(funcs[i]); + } + } + } + + static void LoadDbiStream(BitAccess bits, + out DbiModuleInfo[] modules, + out DbiDbgHdr header, + bool readStrings) { + DbiHeader dh = new DbiHeader(bits); + header = new DbiDbgHdr(); + + if (dh.sig != -1 || dh.ver != 19990903) { + throw new PdbException("Unsupported DBI Stream version, sig={0}, ver={1}", + dh.sig, dh.ver); + } + + // Read gpmod section. + ArrayList modList = new ArrayList(); + int end = bits.Position + dh.gpmodiSize; + while (bits.Position < end) { + DbiModuleInfo mod = new DbiModuleInfo(bits, readStrings); + modList.Add(mod); + } + if (bits.Position != end) { + throw new PdbDebugException("Error reading DBI stream, pos={0} != {1}", + bits.Position, end); + } + + if (modList.Count > 0) { + modules = (DbiModuleInfo[])modList.ToArray(typeof(DbiModuleInfo)); + } else { + modules = null; + } + + // Skip the Section Contribution substream. + bits.Position += dh.secconSize; + + // Skip the Section Map substream. + bits.Position += dh.secmapSize; + + // Skip the File Info substream. + bits.Position += dh.filinfSize; + + // Skip the TSM substream. + bits.Position += dh.tsmapSize; + + // Skip the EC substream. + bits.Position += dh.ecinfoSize; + + // Read the optional header. + end = bits.Position + dh.dbghdrSize; + if (dh.dbghdrSize > 0) { + header = new DbiDbgHdr(bits); + } + bits.Position = end; + } + + internal static PdbFunction[] LoadFunctions(Stream read, bool readAllStrings, out int age, out Guid guid) { + BitAccess bits = new BitAccess(512 * 1024); + return LoadFunctions(read, bits, readAllStrings, out age, out guid); + } + + internal static PdbFunction[] LoadFunctions(Stream read, BitAccess bits, bool readAllStrings, out int age, out Guid guid) { + PdbFileHeader head = new PdbFileHeader(read, bits); + PdbReader reader = new PdbReader(read, head.pageSize); + MsfDirectory dir = new MsfDirectory(reader, head, bits); + DbiModuleInfo[] modules = null; + DbiDbgHdr header; + + dir.streams[1].Read(reader, bits); + Dictionary nameIndex = LoadNameIndex(bits, out age, out guid); + int nameStream; + if (!nameIndex.TryGetValue("/names", out nameStream)) { + throw new PdbException("No `name' stream"); + } + + dir.streams[nameStream].Read(reader, bits); + IntHashTable names = LoadNameStream(bits); + + dir.streams[3].Read(reader, bits); + LoadDbiStream(bits, out modules, out header, readAllStrings); + + ArrayList funcList = new ArrayList(); + + if (modules != null) { + for (int m = 0; m < modules.Length; m++) { + if (modules[m].stream > 0) { + dir.streams[modules[m].stream].Read(reader, bits); + LoadFuncsFromDbiModule(bits, modules[m], names, funcList, + readAllStrings, dir, nameIndex, reader); + } + } + } + + PdbFunction[] funcs = (PdbFunction[])funcList.ToArray(typeof(PdbFunction)); + + // After reading the functions, apply the token remapping table if it exists. + if (header.snTokenRidMap != 0 && header.snTokenRidMap != 0xffff) { + dir.streams[header.snTokenRidMap].Read(reader, bits); + uint[] ridMap = new uint[dir.streams[header.snTokenRidMap].Length / 4]; + bits.ReadUInt32(ridMap); + + foreach (PdbFunction func in funcs) { + func.token = 0x06000000 | ridMap[func.token & 0xffffff]; + } + } + + // + Array.Sort(funcs, PdbFunction.byAddress); + //Array.Sort(funcs, PdbFunction.byToken); + return funcs; + } + } +} diff --git a/symbols/pdb/Microsoft.Cci.Pdb/PdbFileHeader.cs b/symbols/pdb/Microsoft.Cci.Pdb/PdbFileHeader.cs new file mode 100644 index 000000000..c35107650 --- /dev/null +++ b/symbols/pdb/Microsoft.Cci.Pdb/PdbFileHeader.cs @@ -0,0 +1,82 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.IO; +using System.Text; + +namespace Microsoft.Cci.Pdb { + internal class PdbFileHeader { + internal PdbFileHeader(int pageSize) { + this.magic = new byte[32] { + 0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, // "Microsof" + 0x74, 0x20, 0x43, 0x2F, 0x43, 0x2B, 0x2B, 0x20, // "t C/C++ " + 0x4D, 0x53, 0x46, 0x20, 0x37, 0x2E, 0x30, 0x30, // "MSF 7.00" + 0x0D, 0x0A, 0x1A, 0x44, 0x53, 0x00, 0x00, 0x00 // "^^^DS^^^" + }; + this.pageSize = pageSize; + this.zero = 0; + } + + internal PdbFileHeader(Stream reader, BitAccess bits) { + bits.MinCapacity(56); + reader.Seek(0, SeekOrigin.Begin); + bits.FillBuffer(reader, 56); + + this.magic = new byte[32]; + bits.ReadBytes(this.magic); // 0..31 + bits.ReadInt32(out this.pageSize); // 32..35 + bits.ReadInt32(out this.freePageMap); // 36..39 + bits.ReadInt32(out this.pagesUsed); // 40..43 + bits.ReadInt32(out this.directorySize); // 44..47 + bits.ReadInt32(out this.zero); // 48..51 + bits.ReadInt32(out this.directoryRoot); // 52..55 + } + + internal string Magic { + get { return StringFromBytesUTF8(magic); } + } + + internal void Write(Stream writer, BitAccess bits) { + bits.MinCapacity(56); + bits.WriteBytes(magic); // 0..31 + bits.WriteInt32(pageSize); // 32..35 + bits.WriteInt32(freePageMap); // 36..39 + bits.WriteInt32(pagesUsed); // 40..43 + bits.WriteInt32(directorySize); // 44..47 + bits.WriteInt32(zero); // 48..51 + bits.WriteInt32(directoryRoot); // 52..55 + + writer.Seek(0, SeekOrigin.Begin); + bits.WriteBuffer(writer, 56); + } + + //////////////////////////////////////////////////// Helper Functions. + // + internal string StringFromBytesUTF8(byte[] bytes) { + return StringFromBytesUTF8(bytes, 0, bytes.Length); + } + + internal string StringFromBytesUTF8(byte[] bytes, int offset, int length) { + for (int i = 0; i < length; i++) { + if (bytes[offset + i] < ' ') { + length = i; + } + } + return Encoding.UTF8.GetString(bytes, offset, length); + } + + ////////////////////////////////////////////////////////////// Fields. + // + internal readonly byte[] magic; + internal readonly int pageSize; + internal int freePageMap; + internal int pagesUsed; + internal int directorySize; + internal readonly int zero; + internal int directoryRoot; + } + +} diff --git a/symbols/pdb/Microsoft.Cci.Pdb/PdbFunction.cs b/symbols/pdb/Microsoft.Cci.Pdb/PdbFunction.cs new file mode 100644 index 000000000..be284204d --- /dev/null +++ b/symbols/pdb/Microsoft.Cci.Pdb/PdbFunction.cs @@ -0,0 +1,399 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Microsoft.Cci.Pdb { + internal class PdbFunction { + static internal readonly Guid msilMetaData = new Guid(0xc6ea3fc9, 0x59b3, 0x49d6, 0xbc, 0x25, + 0x09, 0x02, 0xbb, 0xab, 0xb4, 0x60); + static internal readonly IComparer byAddress = new PdbFunctionsByAddress(); + static internal readonly IComparer byToken = new PdbFunctionsByToken(); + + internal uint token; + internal uint slotToken; + internal string name; + internal string module; + internal ushort flags; + + internal uint segment; + internal uint address; + internal uint length; + + //internal byte[] metadata; + internal PdbScope[] scopes; + internal PdbLines[] lines; + internal ushort[]/*?*/ usingCounts; + internal IEnumerable/*?*/ namespaceScopes; + internal string/*?*/ iteratorClass; + internal List/*?*/ iteratorScopes; + + private static string StripNamespace(string module) { + int li = module.LastIndexOf('.'); + if (li > 0) { + return module.Substring(li + 1); + } + return module; + } + + + internal static PdbFunction[] LoadManagedFunctions(string module, + BitAccess bits, uint limit, + bool readStrings) { + string mod = StripNamespace(module); + int begin = bits.Position; + int count = 0; + + while (bits.Position < limit) { + ushort siz; + ushort rec; + + bits.ReadUInt16(out siz); + int star = bits.Position; + int stop = bits.Position + siz; + bits.Position = star; + bits.ReadUInt16(out rec); + + switch ((SYM)rec) { + case SYM.S_GMANPROC: + case SYM.S_LMANPROC: + ManProcSym proc; + bits.ReadUInt32(out proc.parent); + bits.ReadUInt32(out proc.end); + bits.Position = (int)proc.end; + count++; + break; + + case SYM.S_END: + bits.Position = stop; + break; + + default: + //Console.WriteLine("{0,6}: {1:x2} {2}", + // bits.Position, rec, (SYM)rec); + bits.Position = stop; + break; + } + } + if (count == 0) { + return null; + } + + bits.Position = begin; + PdbFunction[] funcs = new PdbFunction[count]; + int func = 0; + + while (bits.Position < limit) { + ushort siz; + ushort rec; + + bits.ReadUInt16(out siz); + int star = bits.Position; + int stop = bits.Position + siz; + bits.ReadUInt16(out rec); + + switch ((SYM)rec) { + + case SYM.S_GMANPROC: + case SYM.S_LMANPROC: + ManProcSym proc; + int offset = bits.Position; + + bits.ReadUInt32(out proc.parent); + bits.ReadUInt32(out proc.end); + bits.ReadUInt32(out proc.next); + bits.ReadUInt32(out proc.len); + bits.ReadUInt32(out proc.dbgStart); + bits.ReadUInt32(out proc.dbgEnd); + bits.ReadUInt32(out proc.token); + bits.ReadUInt32(out proc.off); + bits.ReadUInt16(out proc.seg); + bits.ReadUInt8(out proc.flags); + bits.ReadUInt16(out proc.retReg); + if (readStrings) { + bits.ReadCString(out proc.name); + } else { + bits.SkipCString(out proc.name); + } + //Console.WriteLine("token={0:X8} [{1}::{2}]", proc.token, module, proc.name); + + bits.Position = stop; + funcs[func++] = new PdbFunction(module, proc, bits); + break; + + default: { + //throw new PdbDebugException("Unknown SYMREC {0}", (SYM)rec); + bits.Position = stop; + break; + } + } + } + return funcs; + } + + internal static void CountScopesAndSlots(BitAccess bits, uint limit, + out int constants, out int scopes, out int slots, out int usedNamespaces) { + int pos = bits.Position; + BlockSym32 block; + constants = 0; + slots = 0; + scopes = 0; + usedNamespaces = 0; + + while (bits.Position < limit) { + ushort siz; + ushort rec; + + bits.ReadUInt16(out siz); + int star = bits.Position; + int stop = bits.Position + siz; + bits.Position = star; + bits.ReadUInt16(out rec); + + switch ((SYM)rec) { + case SYM.S_BLOCK32: { + bits.ReadUInt32(out block.parent); + bits.ReadUInt32(out block.end); + + scopes++; + bits.Position = (int)block.end; + break; + } + + case SYM.S_MANSLOT: + slots++; + bits.Position = stop; + break; + + case SYM.S_UNAMESPACE: + usedNamespaces++; + bits.Position = stop; + break; + + case SYM.S_MANCONSTANT: + constants++; + bits.Position = stop; + break; + + default: + bits.Position = stop; + break; + } + } + bits.Position = pos; + } + + internal PdbFunction() { + } + + internal PdbFunction(string module, ManProcSym proc, BitAccess bits) { + this.token = proc.token; + this.module = module; + this.name = proc.name; + this.flags = proc.flags; + this.segment = proc.seg; + this.address = proc.off; + this.length = proc.len; + this.slotToken = 0; + + if (proc.seg != 1) { + throw new PdbDebugException("Segment is {0}, not 1.", proc.seg); + } + if (proc.parent != 0 || proc.next != 0) { + throw new PdbDebugException("Warning parent={0}, next={1}", + proc.parent, proc.next); + } + if (proc.dbgStart != 0 || proc.dbgEnd != 0) { + throw new PdbDebugException("Warning DBG start={0}, end={1}", + proc.dbgStart, proc.dbgEnd); + } + + int constantCount; + int scopeCount; + int slotCount; + int usedNamespacesCount; + CountScopesAndSlots(bits, proc.end, out constantCount, out scopeCount, out slotCount, out usedNamespacesCount); + scopes = new PdbScope[scopeCount]; + int scope = 0; + + while (bits.Position < proc.end) { + ushort siz; + ushort rec; + + bits.ReadUInt16(out siz); + int star = bits.Position; + int stop = bits.Position + siz; + bits.Position = star; + bits.ReadUInt16(out rec); + + switch ((SYM)rec) { + case SYM.S_OEM: { // 0x0404 + OemSymbol oem; + + bits.ReadGuid(out oem.idOem); + bits.ReadUInt32(out oem.typind); + // internal byte[] rgl; // user data, force 4-byte alignment + + if (oem.idOem == msilMetaData) { + string name = bits.ReadString(); + if (name == "MD2") { + byte version; + bits.ReadUInt8(out version); + if (version == 4) { + byte count; + bits.ReadUInt8(out count); + bits.Align(4); + while (count-- > 0) + this.ReadCustomMetadata(bits); + } + } + bits.Position = stop; + break; + } else { + throw new PdbDebugException("OEM section: guid={0} ti={1}", + oem.idOem, oem.typind); + // bits.Position = stop; + } + } + + case SYM.S_BLOCK32: { + BlockSym32 block = new BlockSym32(); + + bits.ReadUInt32(out block.parent); + bits.ReadUInt32(out block.end); + bits.ReadUInt32(out block.len); + bits.ReadUInt32(out this.address); + bits.ReadUInt16(out block.seg); + bits.SkipCString(out block.name); + bits.Position = stop; + + scopes[scope] = new PdbScope(block, bits, out slotToken); + bits.Position = (int)block.end; + break; + } + + case SYM.S_UNAMESPACE: + bits.Position = stop; + break; + + case SYM.S_END: + bits.Position = stop; + break; + + default: { + //throw new PdbDebugException("Unknown SYM: {0}", (SYM)rec); + bits.Position = stop; + break; + } + } + } + + if (bits.Position != proc.end) { + throw new PdbDebugException("Not at S_END"); + } + + ushort esiz; + ushort erec; + bits.ReadUInt16(out esiz); + bits.ReadUInt16(out erec); + + if (erec != (ushort)SYM.S_END) { + throw new PdbDebugException("Missing S_END"); + } + } + + private void ReadCustomMetadata(BitAccess bits) { + int savedPosition = bits.Position; + byte version; + bits.ReadUInt8(out version); + if (version != 4) { + throw new PdbDebugException("Unknown custom metadata item version: {0}", version); + } + byte kind; + bits.ReadUInt8(out kind); + bits.Align(4); + uint numberOfBytesInItem; + bits.ReadUInt32(out numberOfBytesInItem); + switch (kind) { + case 0: this.ReadUsingInfo(bits); break; + case 1: this.ReadForwardInfo(bits); break; + case 2: this.ReadForwardedToModuleInfo(bits); break; + case 3: this.ReadIteratorLocals(bits); break; + case 4: this.ReadForwardIterator(bits); break; + default: throw new PdbDebugException("Unknown custom metadata item kind: {0}", kind); + } + bits.Position = savedPosition+(int)numberOfBytesInItem; + } + + private void ReadForwardIterator(BitAccess bits) { + this.iteratorClass = bits.ReadString(); + } + + private void ReadIteratorLocals(BitAccess bits) { + uint numberOfLocals; + bits.ReadUInt32(out numberOfLocals); + this.iteratorScopes = new List((int)numberOfLocals); + while (numberOfLocals-- > 0) { + uint ilStartOffset; + uint ilEndOffset; + bits.ReadUInt32(out ilStartOffset); + bits.ReadUInt32(out ilEndOffset); + this.iteratorScopes.Add(new PdbIteratorScope(ilStartOffset, ilEndOffset-ilStartOffset)); + } + } + + private void ReadForwardedToModuleInfo(BitAccess bits) { + } + + private void ReadForwardInfo(BitAccess bits) { + } + + private void ReadUsingInfo(BitAccess bits) { + ushort numberOfNamespaces; + bits.ReadUInt16(out numberOfNamespaces); + this.usingCounts = new ushort[numberOfNamespaces]; + for (ushort i = 0; i < numberOfNamespaces; i++) { + bits.ReadUInt16(out this.usingCounts[i]); + } + } + + internal class PdbFunctionsByAddress : IComparer { + public int Compare(Object x, Object y) { + PdbFunction fx = (PdbFunction)x; + PdbFunction fy = (PdbFunction)y; + + if (fx.segment < fy.segment) { + return -1; + } else if (fx.segment > fy.segment) { + return 1; + } else if (fx.address < fy.address) { + return -1; + } else if (fx.address > fy.address) { + return 1; + } else { + return 0; + } + } + } + + internal class PdbFunctionsByToken : IComparer { + public int Compare(Object x, Object y) { + PdbFunction fx = (PdbFunction)x; + PdbFunction fy = (PdbFunction)y; + + if (fx.token < fy.token) { + return -1; + } else if (fx.token > fy.token) { + return 1; + } else { + return 0; + } + } + + } + } +} diff --git a/symbols/pdb/Microsoft.Cci.Pdb/PdbLine.cs b/symbols/pdb/Microsoft.Cci.Pdb/PdbLine.cs new file mode 100644 index 000000000..78eb9d630 --- /dev/null +++ b/symbols/pdb/Microsoft.Cci.Pdb/PdbLine.cs @@ -0,0 +1,24 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; + +namespace Microsoft.Cci.Pdb { + internal struct PdbLine { + internal uint offset; + internal uint lineBegin; + internal uint lineEnd; + internal ushort colBegin; + internal ushort colEnd; + + internal PdbLine(uint offset, uint lineBegin, ushort colBegin, uint lineEnd, ushort colEnd) { + this.offset = offset; + this.lineBegin = lineBegin; + this.colBegin = colBegin; + this.lineEnd = lineEnd; + this.colEnd = colEnd; + } + } +} diff --git a/symbols/pdb/Microsoft.Cci.Pdb/PdbLines.cs b/symbols/pdb/Microsoft.Cci.Pdb/PdbLines.cs new file mode 100644 index 000000000..9e989cdf3 --- /dev/null +++ b/symbols/pdb/Microsoft.Cci.Pdb/PdbLines.cs @@ -0,0 +1,18 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; + +namespace Microsoft.Cci.Pdb { + internal class PdbLines { + internal PdbSource file; + internal PdbLine[] lines; + + internal PdbLines(PdbSource file, uint count) { + this.file = file; + this.lines = new PdbLine[count]; + } + } +} diff --git a/symbols/pdb/Microsoft.Cci.Pdb/PdbReader.cs b/symbols/pdb/Microsoft.Cci.Pdb/PdbReader.cs new file mode 100644 index 000000000..52a8f2a2f --- /dev/null +++ b/symbols/pdb/Microsoft.Cci.Pdb/PdbReader.cs @@ -0,0 +1,35 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.IO; + +namespace Microsoft.Cci.Pdb { + internal class PdbReader { + internal PdbReader(Stream reader, int pageSize) { + this.pageSize = pageSize; + this.reader = reader; + } + + internal void Seek(int page, int offset) { + reader.Seek(page * pageSize + offset, SeekOrigin.Begin); + } + + internal void Read(byte[] bytes, int offset, int count) { + reader.Read(bytes, offset, count); + } + + internal int PagesFromSize(int size) { + return (size + pageSize - 1) / (pageSize); + } + + internal int PageSize { + get { return pageSize; } + } + + internal readonly int pageSize; + internal readonly Stream reader; + } +} diff --git a/symbols/pdb/Microsoft.Cci.Pdb/PdbScope.cs b/symbols/pdb/Microsoft.Cci.Pdb/PdbScope.cs new file mode 100644 index 000000000..72a68d780 --- /dev/null +++ b/symbols/pdb/Microsoft.Cci.Pdb/PdbScope.cs @@ -0,0 +1,104 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; + +namespace Microsoft.Cci.Pdb { + internal class PdbScope { + internal PdbConstant[] constants; + internal PdbSlot[] slots; + internal PdbScope[] scopes; + internal string[] usedNamespaces; + + internal uint segment; + internal uint address; + internal uint length; + + internal PdbScope(BlockSym32 block, BitAccess bits, out uint typind) { + this.segment = block.seg; + this.address = block.off; + this.length = block.len; + typind = 0; + + int constantCount; + int scopeCount; + int slotCount; + int namespaceCount; + PdbFunction.CountScopesAndSlots(bits, block.end, out constantCount, out scopeCount, out slotCount, out namespaceCount); + constants = new PdbConstant[constantCount]; + scopes = new PdbScope[scopeCount]; + slots = new PdbSlot[slotCount]; + usedNamespaces = new string[namespaceCount]; + int constant = 0; + int scope = 0; + int slot = 0; + int usedNs = 0; + + while (bits.Position < block.end) { + ushort siz; + ushort rec; + + bits.ReadUInt16(out siz); + int star = bits.Position; + int stop = bits.Position + siz; + bits.Position = star; + bits.ReadUInt16(out rec); + + switch ((SYM)rec) { + case SYM.S_BLOCK32: { + BlockSym32 sub = new BlockSym32(); + + bits.ReadUInt32(out sub.parent); + bits.ReadUInt32(out sub.end); + bits.ReadUInt32(out sub.len); + bits.ReadUInt32(out sub.off); + bits.ReadUInt16(out sub.seg); + bits.SkipCString(out sub.name); + + bits.Position = stop; + scopes[scope++] = new PdbScope(sub, bits, out typind); + break; + } + + case SYM.S_MANSLOT: + slots[slot++] = new PdbSlot(bits, out typind); + bits.Position = stop; + break; + + case SYM.S_UNAMESPACE: + bits.ReadCString(out usedNamespaces[usedNs++]); + bits.Position = stop; + break; + + case SYM.S_END: + bits.Position = stop; + break; + + case SYM.S_MANCONSTANT: + constants[constant++] = new PdbConstant(bits); + bits.Position = stop; + break; + + default: + throw new PdbException("Unknown SYM in scope {0}", (SYM)rec); + // bits.Position = stop; + } + } + + if (bits.Position != block.end) { + throw new Exception("Not at S_END"); + } + + ushort esiz; + ushort erec; + bits.ReadUInt16(out esiz); + bits.ReadUInt16(out erec); + + if (erec != (ushort)SYM.S_END) { + throw new Exception("Missing S_END"); + } + } + } +} diff --git a/symbols/pdb/Microsoft.Cci.Pdb/PdbSlot.cs b/symbols/pdb/Microsoft.Cci.Pdb/PdbSlot.cs new file mode 100644 index 000000000..b2cebbeb9 --- /dev/null +++ b/symbols/pdb/Microsoft.Cci.Pdb/PdbSlot.cs @@ -0,0 +1,35 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; + +namespace Microsoft.Cci.Pdb { + internal class PdbSlot { + internal uint slot; + internal string name; + internal ushort flags; + internal uint segment; + internal uint address; + + internal PdbSlot(BitAccess bits, out uint typind) { + AttrSlotSym slot; + + bits.ReadUInt32(out slot.index); + bits.ReadUInt32(out slot.typind); + bits.ReadUInt32(out slot.offCod); + bits.ReadUInt16(out slot.segCod); + bits.ReadUInt16(out slot.flags); + bits.ReadCString(out slot.name); + + this.slot = slot.index; + this.name = slot.name; + this.flags = slot.flags; + this.segment = slot.segCod; + this.address = slot.offCod; + + typind = slot.typind; + } + } +} diff --git a/symbols/pdb/Microsoft.Cci.Pdb/PdbSource.cs b/symbols/pdb/Microsoft.Cci.Pdb/PdbSource.cs new file mode 100644 index 000000000..e7b0e3402 --- /dev/null +++ b/symbols/pdb/Microsoft.Cci.Pdb/PdbSource.cs @@ -0,0 +1,24 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; + +namespace Microsoft.Cci.Pdb { + internal class PdbSource { + internal uint index; + internal string name; + internal Guid doctype; + internal Guid language; + internal Guid vendor; + + internal PdbSource(uint index, string name, Guid doctype, Guid language, Guid vendor) { + this.index = index; + this.name = name; + this.doctype = doctype; + this.language = language; + this.vendor = vendor; + } + } +} diff --git a/symbols/pdb/Microsoft.Cci.Pdb/PdbWriter.cs b/symbols/pdb/Microsoft.Cci.Pdb/PdbWriter.cs new file mode 100644 index 000000000..ca4992eed --- /dev/null +++ b/symbols/pdb/Microsoft.Cci.Pdb/PdbWriter.cs @@ -0,0 +1,129 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.IO; + +namespace Microsoft.Cci.Pdb { + internal class PdbWriter { + internal PdbWriter(Stream writer, int pageSize) { + this.pageSize = pageSize; + this.usedBytes = pageSize * 3; + this.writer = writer; + + writer.SetLength(usedBytes); + } + + internal void WriteMeta(DataStream[] streams, BitAccess bits) { + PdbFileHeader head = new PdbFileHeader(pageSize); + + WriteDirectory(streams, + out head.directoryRoot, + out head.directorySize, + bits); + WriteFreeMap(); + + head.freePageMap = 2; + head.pagesUsed = usedBytes / pageSize; + + writer.Seek(0, SeekOrigin.Begin); + head.Write(writer, bits); + } + + private void WriteDirectory(DataStream[] streams, + out int directoryRoot, + out int directorySize, + BitAccess bits) { + DataStream directory = new DataStream(); + + int pages = 0; + for (int s = 0; s < streams.Length; s++) { + if (streams[s].Length > 0) { + pages += streams[s].Pages; + } + } + + int use = 4 * (1 + streams.Length + pages); + bits.MinCapacity(use); + bits.WriteInt32(streams.Length); + for (int s = 0; s < streams.Length; s++) { + bits.WriteInt32(streams[s].Length); + } + for (int s = 0; s < streams.Length; s++) { + if (streams[s].Length > 0) { + bits.WriteInt32(streams[s].pages); + } + } + directory.Write(this, bits.Buffer, use); + directorySize = directory.Length; + + use = 4 * directory.Pages; + bits.MinCapacity(use); + bits.WriteInt32(directory.pages); + + DataStream ddir = new DataStream(); + ddir.Write(this, bits.Buffer, use); + + directoryRoot = ddir.pages[0]; + } + + private void WriteFreeMap() { + byte[] buffer = new byte[pageSize]; + + // We configure the old free map with only the first 3 pages allocated. + buffer[0] = 0xf8; + for (int i = 1; i < pageSize; i++) { + buffer[i] = 0xff; + } + Seek(1, 0); + Write(buffer, 0, pageSize); + + // We configure the new free map with all of the used pages gone. + int count = usedBytes / pageSize; + int full = count / 8; + for (int i = 0; i < full; i++) { + buffer[i] = 0; + } + int rema = count % 8; + buffer[full] = (byte)(0xff << rema); + + Seek(2, 0); + Write(buffer, 0, pageSize); + } + + internal int AllocatePages(int count) { + int begin = usedBytes; + + usedBytes += count * pageSize; + writer.SetLength(usedBytes); + + if (usedBytes > pageSize * pageSize * 8) { + throw new Exception("PdbWriter does not support multiple free maps."); + } + return begin / pageSize; + } + + internal void Seek(int page, int offset) { + writer.Seek(page * pageSize + offset, SeekOrigin.Begin); + } + + internal void Write(byte[] bytes, int offset, int count) { + writer.Write(bytes, offset, count); + } + + ////////////////////////////////////////////////////////////////////// + // + internal int PageSize { + get { return pageSize; } + } + + ////////////////////////////////////////////////////////////////////// + // + internal readonly int pageSize; + private Stream writer; + private int usedBytes; + } + +} diff --git a/symbols/pdb/Microsoft.Cci.Pdb/SourceLocationProvider.cs b/symbols/pdb/Microsoft.Cci.Pdb/SourceLocationProvider.cs new file mode 100644 index 000000000..2b28971cb --- /dev/null +++ b/symbols/pdb/Microsoft.Cci.Pdb/SourceLocationProvider.cs @@ -0,0 +1,66 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.IO; +using Microsoft.Cci; +using Microsoft.Cci.Pdb; +using System.Text; +using System.Diagnostics.SymbolStore; + +namespace Microsoft.Cci { + + internal sealed class UsedNamespace : IUsedNamespace { + + internal UsedNamespace(IName alias, IName namespaceName) { + this.alias = alias; + this.namespaceName = namespaceName; + } + + public IName Alias { + get { return this.alias; } + } + readonly IName alias; + + public IName NamespaceName { + get { return this.namespaceName; } + } + readonly IName namespaceName; + + } + + internal class NamespaceScope : INamespaceScope { + + internal NamespaceScope(IEnumerable usedNamespaces) { + this.usedNamespaces = usedNamespaces; + } + + public IEnumerable UsedNamespaces { + get { return this.usedNamespaces; } + } + readonly IEnumerable usedNamespaces; + + } + + internal sealed class PdbIteratorScope : ILocalScope { + + internal PdbIteratorScope(uint offset, uint length) { + this.offset = offset; + this.length = length; + } + + public uint Offset { + get { return this.offset; } + } + uint offset; + + public uint Length { + get { return this.length; } + } + uint length; + + } +} \ No newline at end of file diff --git a/symbols/pdb/Mono.Cecil.Pdb.csproj b/symbols/pdb/Mono.Cecil.Pdb.csproj new file mode 100644 index 000000000..d0f6fe4ef --- /dev/null +++ b/symbols/pdb/Mono.Cecil.Pdb.csproj @@ -0,0 +1,130 @@ + + + + net_4_0_Debug + AnyCPU + 9.0.30729 + 2.0 + {63E6915C-7EA4-4D76-AB28-0D7191EEA626} + Library + Properties + Mono.Cecil.Pdb + Mono.Cecil.Pdb + 512 + true + ..\..\mono.snk + + + true + full + false + ..\..\bin\net_2_0_Debug\ + DEBUG;TRACE + prompt + 4 + v2.0 + + + pdbonly + true + ..\..\bin\net_2_0_Release\ + TRACE + prompt + 4 + v2.0 + + + true + full + false + ..\..\bin\net_3_5_Debug\ + DEBUG;TRACE;NET_3_5 + prompt + 4 + v3.5 + + + pdbonly + true + ..\..\bin\net_3_5_Release\ + TRACE;NET_3_5 + prompt + 4 + v3.5 + + + true + full + false + ..\..\bin\net_4_0_Debug\ + DEBUG;TRACE;NET_3_5;NET_4_0 + prompt + 4 + v4.0 + + + pdbonly + true + ..\..\bin\net_4_0_Release\ + TRACE;NET_3_5;NET_4_0 + prompt + 4 + v4.0 + + + + + + + + + + {D68133BD-1E63-496E-9EDE-4FBDBF77B486} + Mono.Cecil + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/symbols/pdb/Mono.Cecil.Pdb/AssemblyInfo.cs b/symbols/pdb/Mono.Cecil.Pdb/AssemblyInfo.cs new file mode 100644 index 000000000..a9a7b90db --- /dev/null +++ b/symbols/pdb/Mono.Cecil.Pdb/AssemblyInfo.cs @@ -0,0 +1,41 @@ +// +// AssemblyInfo.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Reflection; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle ("Mono.Cecil.Pdb")] +[assembly: AssemblyProduct ("Mono.Cecil")] +[assembly: AssemblyCopyright ("Copyright © 2008 - 2010 Jb Evain")] + +[assembly: CLSCompliant (false)] +[assembly: ComVisible (false)] + +[assembly: AssemblyVersion ("0.9.4.0")] +[assembly: AssemblyFileVersion ("0.9.4.0")] diff --git a/symbols/pdb/Mono.Cecil.Pdb/ISymUnmanagedDocumentWriter.cs b/symbols/pdb/Mono.Cecil.Pdb/ISymUnmanagedDocumentWriter.cs new file mode 100644 index 000000000..8f47b2c0f --- /dev/null +++ b/symbols/pdb/Mono.Cecil.Pdb/ISymUnmanagedDocumentWriter.cs @@ -0,0 +1,41 @@ +// ISymUnmanagedDocumentWriter.cs +// +// Author: +// Juerg Billeter (j@bitron.ch) +// +// (C) 2008 Juerg Billeter +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System.Runtime.InteropServices; + +#if !READ_ONLY + +namespace Mono.Cecil.Pdb { + + [Guid ("B01FAFEB-C450-3A4D-BEEC-B4CEEC01E006")] + [InterfaceType (ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + interface ISymUnmanagedDocumentWriter { + } +} + +#endif diff --git a/symbols/pdb/Mono.Cecil.Pdb/ISymUnmanagedWriter2.cs b/symbols/pdb/Mono.Cecil.Pdb/ISymUnmanagedWriter2.cs new file mode 100644 index 000000000..11466dcb9 --- /dev/null +++ b/symbols/pdb/Mono.Cecil.Pdb/ISymUnmanagedWriter2.cs @@ -0,0 +1,103 @@ +// +// ISymUnmanagedWriter2.cs +// +// Author: +// Juerg Billeter (j@bitron.ch) +// +// (C) 2008 Juerg Billeter +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Diagnostics.SymbolStore; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.ComTypes; + +using Mono.Cecil.Cil; + +#if !READ_ONLY + +namespace Mono.Cecil.Pdb { + + [Guid ("0B97726E-9E6D-4f05-9A26-424022093CAA")] + [InterfaceType (ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + interface ISymUnmanagedWriter2 { + + void DefineDocument ( + [In, MarshalAs (UnmanagedType.LPWStr)] string url, + [In] ref Guid langauge, + [In] ref Guid languageVendor, + [In] ref Guid documentType, + [Out, MarshalAs (UnmanagedType.Interface)] out ISymUnmanagedDocumentWriter pRetVal); + void SetUserEntryPoint ([In] SymbolToken method); + void OpenMethod ([In] SymbolToken method); + void CloseMethod (); + void OpenScope ([In] int startOffset, [Out] out int pRetVal); + void CloseScope ([In] int endOffset); + void SetScopeRange_Placeholder (); + void DefineLocalVariable_Placeholder (); + void DefineParameter_Placeholder (); + void DefineField_Placeholder (); + void DefineGlobalVariable_Placeholder (); + void Close (); + void SetSymAttribute_Placeholder (); + void OpenNamespace ([In, MarshalAs (UnmanagedType.LPWStr)] string name); + void CloseNamespace (); + void UsingNamespace ([In, MarshalAs (UnmanagedType.LPWStr)] string fullName); + void SetMethodSourceRange_Placeholder (); + void Initialize ( + [In, MarshalAs (UnmanagedType.IUnknown)] object emitter, + [In, MarshalAs (UnmanagedType.LPWStr)] string filename, + [In] IStream pIStream, + [In] bool fFullBuild); + void GetDebugInfo ( + [Out] out ImageDebugDirectory pIDD, + [In] int cData, + [Out] out int pcData, + [In, Out, MarshalAs (UnmanagedType.LPArray, SizeParamIndex = 1)] byte [] data); + void DefineSequencePoints ( + [In, MarshalAs (UnmanagedType.Interface)] ISymUnmanagedDocumentWriter document, + [In] int spCount, + [In, MarshalAs (UnmanagedType.LPArray, SizeParamIndex = 1)] int [] offsets, + [In, MarshalAs (UnmanagedType.LPArray, SizeParamIndex = 1)] int [] lines, + [In, MarshalAs (UnmanagedType.LPArray, SizeParamIndex = 1)] int [] columns, + [In, MarshalAs (UnmanagedType.LPArray, SizeParamIndex = 1)] int [] endLines, + [In, MarshalAs (UnmanagedType.LPArray, SizeParamIndex = 1)] int [] endColumns); + void RemapToken_Placeholder (); + void Initialize2_Placeholder (); + void DefineConstant_Placeholder (); + void Abort_Placeholder (); + + void DefineLocalVariable2 ( + [In, MarshalAs (UnmanagedType.LPWStr)] string name, + [In] int attributes, + [In] SymbolToken sigToken, + [In] int addrKind, + [In] int addr1, + [In] int addr2, + [In] int addr3, + [In] int startOffset, + [In] int endOffset); + } +} + +#endif diff --git a/symbols/pdb/Mono.Cecil.Pdb/ModuleMetadata.cs b/symbols/pdb/Mono.Cecil.Pdb/ModuleMetadata.cs new file mode 100644 index 000000000..6509f0773 --- /dev/null +++ b/symbols/pdb/Mono.Cecil.Pdb/ModuleMetadata.cs @@ -0,0 +1,715 @@ +using System; +using System.Runtime.InteropServices; +using System.Text; + +#if !READ_ONLY + +namespace Mono.Cecil.Pdb { + + [ComImport, InterfaceType (ComInterfaceType.InterfaceIsIUnknown), Guid ("BA3FEE4C-ECB9-4e41-83B7-183FA41CD859")] + interface IMetaDataEmit { + void SetModuleProps (string szName); + void Save (string szFile, uint dwSaveFlags); + void SaveToStream (IntPtr pIStream, uint dwSaveFlags); + uint GetSaveSize (uint fSave); + uint DefineTypeDef (IntPtr szTypeDef, uint dwTypeDefFlags, uint tkExtends, IntPtr rtkImplements); + uint DefineNestedType (IntPtr szTypeDef, uint dwTypeDefFlags, uint tkExtends, IntPtr rtkImplements, uint tdEncloser); + void SetHandler ([MarshalAs (UnmanagedType.IUnknown), In]object pUnk); + uint DefineMethod (uint td, IntPtr zName, uint dwMethodFlags, IntPtr pvSigBlob, uint cbSigBlob, uint ulCodeRVA, uint dwImplFlags); + void DefineMethodImpl (uint td, uint tkBody, uint tkDecl); + uint DefineTypeRefByName (uint tkResolutionScope, IntPtr szName); + uint DefineImportType (IntPtr pAssemImport, IntPtr pbHashValue, uint cbHashValue, IMetaDataImport pImport, + uint tdImport, IntPtr pAssemEmit); + uint DefineMemberRef (uint tkImport, string szName, IntPtr pvSigBlob, uint cbSigBlob); + uint DefineImportMember (IntPtr pAssemImport, IntPtr /* void* */ pbHashValue, uint cbHashValue, + IMetaDataImport pImport, uint mbMember, IntPtr pAssemEmit, uint tkParent); + uint DefineEvent (uint td, string szEvent, uint dwEventFlags, uint tkEventType, uint mdAddOn, uint mdRemoveOn, uint mdFire, IntPtr /* uint* */ rmdOtherMethods); + void SetClassLayout (uint td, uint dwPackSize, IntPtr /*COR_FIELD_OFFSET**/ rFieldOffsets, uint ulClassSize); + void DeleteClassLayout (uint td); + void SetFieldMarshal (uint tk, IntPtr /* byte* */ pvNativeType, uint cbNativeType); + void DeleteFieldMarshal (uint tk); + uint DefinePermissionSet (uint tk, uint dwAction, IntPtr /* void* */ pvPermission, uint cbPermission); + void SetRVA (uint md, uint ulRVA); + uint GetTokenFromSig (IntPtr /* byte* */ pvSig, uint cbSig); + uint DefineModuleRef (string szName); + void SetParent (uint mr, uint tk); + uint GetTokenFromTypeSpec (IntPtr /* byte* */ pvSig, uint cbSig); + void SaveToMemory (IntPtr /* void* */ pbData, uint cbData); + uint DefineUserString (string szString, uint cchString); + void DeleteToken (uint tkObj); + void SetMethodProps (uint md, uint dwMethodFlags, uint ulCodeRVA, uint dwImplFlags); + void SetTypeDefProps (uint td, uint dwTypeDefFlags, uint tkExtends, IntPtr /* uint* */ rtkImplements); + void SetEventProps (uint ev, uint dwEventFlags, uint tkEventType, uint mdAddOn, uint mdRemoveOn, uint mdFire, IntPtr /* uint* */ rmdOtherMethods); + uint SetPermissionSetProps (uint tk, uint dwAction, IntPtr /* void* */ pvPermission, uint cbPermission); + void DefinePinvokeMap (uint tk, uint dwMappingFlags, string szImportName, uint mrImportDLL); + void SetPinvokeMap (uint tk, uint dwMappingFlags, string szImportName, uint mrImportDLL); + void DeletePinvokeMap (uint tk); + uint DefineCustomAttribute (uint tkObj, uint tkType, IntPtr /* void* */ pCustomAttribute, uint cbCustomAttribute); + void SetCustomAttributeValue (uint pcv, IntPtr /* void* */ pCustomAttribute, uint cbCustomAttribute); + uint DefineField (uint td, string szName, uint dwFieldFlags, IntPtr /* byte* */ pvSigBlob, uint cbSigBlob, uint dwCPlusTypeFlag, IntPtr /* void* */ pValue, uint cchValue); + uint DefineProperty (uint td, string szProperty, uint dwPropFlags, IntPtr /* byte* */ pvSig, uint cbSig, uint dwCPlusTypeFlag, + IntPtr /* void* */ pValue, uint cchValue, uint mdSetter, uint mdGetter, IntPtr /* uint* */ rmdOtherMethods); + uint DefineParam (uint md, uint ulParamSeq, string szName, uint dwParamFlags, uint dwCPlusTypeFlag, IntPtr /* void* */ pValue, uint cchValue); + void SetFieldProps (uint fd, uint dwFieldFlags, uint dwCPlusTypeFlag, IntPtr /* void* */ pValue, uint cchValue); + void SetPropertyProps (uint pr, uint dwPropFlags, uint dwCPlusTypeFlag, IntPtr /* void* */ pValue, uint cchValue, uint mdSetter, uint mdGetter, IntPtr /* uint* */ rmdOtherMethods); + void SetParamProps (uint pd, string szName, uint dwParamFlags, uint dwCPlusTypeFlag, IntPtr /* void* */ pValue, uint cchValue); + uint DefineSecurityAttributeSet (uint tkObj, IntPtr rSecAttrs, uint cSecAttrs); + void ApplyEditAndContinue ([MarshalAs (UnmanagedType.IUnknown)]object pImport); + uint TranslateSigWithScope (IntPtr pAssemImport, IntPtr /* void* */ pbHashValue, uint cbHashValue, + IMetaDataImport import, IntPtr /* byte* */ pbSigBlob, uint cbSigBlob, IntPtr pAssemEmit, IMetaDataEmit emit, IntPtr /* byte* */ pvTranslatedSig, uint cbTranslatedSigMax); + void SetMethodImplFlags (uint md, uint dwImplFlags); + void SetFieldRVA (uint fd, uint ulRVA); + void Merge (IMetaDataImport pImport, IntPtr pHostMapToken, [MarshalAs (UnmanagedType.IUnknown)]object pHandler); + void MergeEnd (); + } + + [ComImport, InterfaceType (ComInterfaceType.InterfaceIsIUnknown), Guid ("7DAC8207-D3AE-4c75-9B67-92801A497D44")] + interface IMetaDataImport { + [PreserveSig] + void CloseEnum (uint hEnum); + uint CountEnum (uint hEnum); + void ResetEnum (uint hEnum, uint ulPos); + uint EnumTypeDefs (ref uint phEnum, [MarshalAs (UnmanagedType.LPArray, SizeParamIndex = 2)] uint [] rTypeDefs, uint cMax); + uint EnumInterfaceImpls (ref uint phEnum, uint td, [MarshalAs (UnmanagedType.LPArray, SizeParamIndex = 3)] uint [] rImpls, uint cMax); + uint EnumTypeRefs (ref uint phEnum, [MarshalAs (UnmanagedType.LPArray, SizeParamIndex = 2)] uint [] rTypeRefs, uint cMax); + uint FindTypeDefByName (string szTypeDef, uint tkEnclosingClass); + Guid GetScopeProps (StringBuilder szName, uint cchName, out uint pchName); + uint GetModuleFromScope (); + uint GetTypeDefProps (uint td, IntPtr szTypeDef, uint cchTypeDef, out uint pchTypeDef, ref uint pdwTypeDefFlags); + uint GetInterfaceImplProps (uint iiImpl, out uint pClass); + uint GetTypeRefProps (uint tr, out uint ptkResolutionScope, StringBuilder szName, uint cchName); + uint ResolveTypeRef (uint tr, [In] ref Guid riid, [MarshalAs (UnmanagedType.Interface)] out object ppIScope); + uint EnumMembers (ref uint phEnum, uint cl, [MarshalAs (UnmanagedType.LPArray, SizeParamIndex = 3)] uint [] rMembers, uint cMax); + uint EnumMembersWithName (ref uint phEnum, uint cl, string szName, [MarshalAs (UnmanagedType.LPArray, SizeParamIndex = 4)] uint [] rMembers, uint cMax); + uint EnumMethods (ref uint phEnum, uint cl, IntPtr /* uint* */ rMethods, uint cMax); + uint EnumMethodsWithName (ref uint phEnum, uint cl, string szName, [MarshalAs (UnmanagedType.LPArray, SizeParamIndex = 4)] uint [] rMethods, uint cMax); + uint EnumFields (ref uint phEnum, uint cl, IntPtr /* uint* */ rFields, uint cMax); + uint EnumFieldsWithName (ref uint phEnum, uint cl, string szName, [MarshalAs (UnmanagedType.LPArray, SizeParamIndex = 4)] uint [] rFields, uint cMax); + uint EnumParams (ref uint phEnum, uint mb, [MarshalAs (UnmanagedType.LPArray, SizeParamIndex = 3)] uint [] rParams, uint cMax); + uint EnumMemberRefs (ref uint phEnum, uint tkParent, [MarshalAs (UnmanagedType.LPArray, SizeParamIndex = 3)] uint [] rMemberRefs, uint cMax); + uint EnumMethodImpls (ref uint phEnum, uint td, [MarshalAs (UnmanagedType.LPArray, SizeParamIndex = 4)] uint [] rMethodBody, + [MarshalAs (UnmanagedType.LPArray, SizeParamIndex = 4)] uint [] rMethodDecl, uint cMax); + uint EnumPermissionSets (ref uint phEnum, uint tk, uint dwActions, [MarshalAs (UnmanagedType.LPArray, SizeParamIndex = 4)] uint [] rPermission, + uint cMax); + uint FindMember (uint td, string szName, [MarshalAs (UnmanagedType.LPArray, SizeParamIndex = 3)] byte [] pvSigBlob, uint cbSigBlob); + uint FindMethod (uint td, string szName, [MarshalAs (UnmanagedType.LPArray, SizeParamIndex = 3)] byte [] pvSigBlob, uint cbSigBlob); + uint FindField (uint td, string szName, [MarshalAs (UnmanagedType.LPArray, SizeParamIndex = 3)] byte [] pvSigBlob, uint cbSigBlob); + uint FindMemberRef (uint td, string szName, [MarshalAs (UnmanagedType.LPArray, SizeParamIndex = 3)] byte [] pvSigBlob, uint cbSigBlob); + uint GetMethodProps (uint mb, out uint pClass, IntPtr szMethod, uint cchMethod, out uint pchMethod, IntPtr pdwAttr, + IntPtr ppvSigBlob, IntPtr pcbSigBlob, IntPtr pulCodeRVA); + uint GetMemberRefProps (uint mr, ref uint ptk, StringBuilder szMember, uint cchMember, out uint pchMember, out IntPtr /* byte* */ ppvSigBlob); + uint EnumProperties (ref uint phEnum, uint td, IntPtr /* uint* */ rProperties, uint cMax); + uint EnumEvents (ref uint phEnum, uint td, IntPtr /* uint* */ rEvents, uint cMax); + uint GetEventProps (uint ev, out uint pClass, StringBuilder szEvent, uint cchEvent, out uint pchEvent, out uint pdwEventFlags, + out uint ptkEventType, out uint pmdAddOn, out uint pmdRemoveOn, out uint pmdFire, + [MarshalAs (UnmanagedType.LPArray, SizeParamIndex = 11)] uint [] rmdOtherMethod, uint cMax); + uint EnumMethodSemantics (ref uint phEnum, uint mb, [MarshalAs (UnmanagedType.LPArray, SizeParamIndex = 3)] uint [] rEventProp, uint cMax); + uint GetMethodSemantics (uint mb, uint tkEventProp); + uint GetClassLayout (uint td, out uint pdwPackSize, [MarshalAs (UnmanagedType.LPArray, SizeParamIndex = 3)] IntPtr /*COR_FIELD_OFFSET **/ rFieldOffset, uint cMax, out uint pcFieldOffset); + uint GetFieldMarshal (uint tk, out IntPtr /* byte* */ ppvNativeType); + uint GetRVA (uint tk, out uint pulCodeRVA); + uint GetPermissionSetProps (uint pm, out uint pdwAction, out IntPtr /* void* */ ppvPermission); + uint GetSigFromToken (uint mdSig, out IntPtr /* byte* */ ppvSig); + uint GetModuleRefProps (uint mur, StringBuilder szName, uint cchName); + uint EnumModuleRefs (ref uint phEnum, [MarshalAs (UnmanagedType.LPArray, SizeParamIndex = 2)] uint [] rModuleRefs, uint cmax); + uint GetTypeSpecFromToken (uint typespec, out IntPtr /* byte* */ ppvSig); + uint GetNameFromToken (uint tk); + uint EnumUnresolvedMethods (ref uint phEnum, [MarshalAs (UnmanagedType.LPArray, SizeParamIndex = 2)] uint [] rMethods, uint cMax); + uint GetUserString (uint stk, StringBuilder szString, uint cchString); + uint GetPinvokeMap (uint tk, out uint pdwMappingFlags, StringBuilder szImportName, uint cchImportName, out uint pchImportName); + uint EnumSignatures (ref uint phEnum, [MarshalAs (UnmanagedType.LPArray, SizeParamIndex = 2)] uint [] rSignatures, uint cmax); + uint EnumTypeSpecs (ref uint phEnum, [MarshalAs (UnmanagedType.LPArray, SizeParamIndex = 2)] uint [] rTypeSpecs, uint cmax); + uint EnumUserStrings (ref uint phEnum, [MarshalAs (UnmanagedType.LPArray, SizeParamIndex = 2)] uint [] rStrings, uint cmax); + [PreserveSig] + int GetParamForMethodIndex (uint md, uint ulParamSeq, out uint pParam); + uint EnumCustomAttributes (ref uint phEnum, uint tk, uint tkType, [MarshalAs (UnmanagedType.LPArray, SizeParamIndex = 4)] uint [] rCustomAttributes, uint cMax); + uint GetCustomAttributeProps (uint cv, out uint ptkObj, out uint ptkType, out IntPtr /* void* */ ppBlob); + uint FindTypeRef (uint tkResolutionScope, string szName); + uint GetMemberProps (uint mb, out uint pClass, StringBuilder szMember, uint cchMember, out uint pchMember, out uint pdwAttr, + out IntPtr /* byte* */ ppvSigBlob, out uint pcbSigBlob, out uint pulCodeRVA, out uint pdwImplFlags, out uint pdwCPlusTypeFlag, out IntPtr /* void* */ ppValue); + uint GetFieldProps (uint mb, out uint pClass, StringBuilder szField, uint cchField, out uint pchField, out uint pdwAttr, + out IntPtr /* byte* */ ppvSigBlob, out uint pcbSigBlob, out uint pdwCPlusTypeFlag, out IntPtr /* void* */ ppValue); + uint GetPropertyProps (uint prop, out uint pClass, StringBuilder szProperty, uint cchProperty, out uint pchProperty, out uint pdwPropFlags, + out IntPtr /* byte* */ ppvSig, out uint pbSig, out uint pdwCPlusTypeFlag, out IntPtr /* void* */ ppDefaultValue, out uint pcchDefaultValue, out uint pmdSetter, + out uint pmdGetter, [MarshalAs (UnmanagedType.LPArray, SizeParamIndex = 14)] uint [] rmdOtherMethod, uint cMax); + uint GetParamProps (uint tk, out uint pmd, out uint pulSequence, StringBuilder szName, uint cchName, out uint pchName, + out uint pdwAttr, out uint pdwCPlusTypeFlag, out IntPtr /* void* */ ppValue); + uint GetCustomAttributeByName (uint tkObj, string szName, out IntPtr /* void* */ ppData); + [PreserveSig] + [return: MarshalAs (UnmanagedType.Bool)] + bool IsValidToken (uint tk); + uint GetNestedClassProps (uint tdNestedClass); + uint GetNativeCallConvFromSig (IntPtr /* void* */ pvSig, uint cbSig); + int IsGlobal (uint pd); + } + + class ModuleMetadata : IMetaDataEmit, IMetaDataImport { + + readonly ModuleDefinition module; + + public ModuleMetadata (ModuleDefinition module) + { + this.module = module; + } + + public void SetModuleProps (string szName) + { + throw new NotImplementedException (); + } + + public void Save (string szFile, uint dwSaveFlags) + { + throw new NotImplementedException (); + } + + public void SaveToStream (IntPtr pIStream, uint dwSaveFlags) + { + throw new NotImplementedException (); + } + + public uint GetSaveSize (uint fSave) + { + throw new NotImplementedException (); + } + + public uint DefineTypeDef (IntPtr szTypeDef, uint dwTypeDefFlags, uint tkExtends, IntPtr rtkImplements) + { + throw new NotImplementedException (); + } + + public uint DefineNestedType (IntPtr szTypeDef, uint dwTypeDefFlags, uint tkExtends, IntPtr rtkImplements, uint tdEncloser) + { + throw new NotImplementedException (); + } + + public void SetHandler (object pUnk) + { + throw new NotImplementedException (); + } + + public uint DefineMethod (uint td, IntPtr zName, uint dwMethodFlags, IntPtr pvSigBlob, uint cbSigBlob, uint ulCodeRVA, uint dwImplFlags) + { + throw new NotImplementedException (); + } + + public void DefineMethodImpl (uint td, uint tkBody, uint tkDecl) + { + throw new NotImplementedException (); + } + + public uint DefineTypeRefByName (uint tkResolutionScope, IntPtr szName) + { + throw new NotImplementedException (); + } + + public uint DefineImportType (IntPtr pAssemImport, IntPtr pbHashValue, uint cbHashValue, IMetaDataImport pImport, uint tdImport, IntPtr pAssemEmit) + { + throw new NotImplementedException (); + } + + public uint DefineMemberRef (uint tkImport, string szName, IntPtr pvSigBlob, uint cbSigBlob) + { + throw new NotImplementedException (); + } + + public uint DefineImportMember (IntPtr pAssemImport, IntPtr pbHashValue, uint cbHashValue, IMetaDataImport pImport, uint mbMember, IntPtr pAssemEmit, uint tkParent) + { + throw new NotImplementedException (); + } + + public uint DefineEvent (uint td, string szEvent, uint dwEventFlags, uint tkEventType, uint mdAddOn, uint mdRemoveOn, uint mdFire, IntPtr rmdOtherMethods) + { + throw new NotImplementedException (); + } + + public void SetClassLayout (uint td, uint dwPackSize, IntPtr rFieldOffsets, uint ulClassSize) + { + throw new NotImplementedException (); + } + + public void DeleteClassLayout (uint td) + { + throw new NotImplementedException (); + } + + public void SetFieldMarshal (uint tk, IntPtr pvNativeType, uint cbNativeType) + { + throw new NotImplementedException (); + } + + public void DeleteFieldMarshal (uint tk) + { + throw new NotImplementedException (); + } + + public uint DefinePermissionSet (uint tk, uint dwAction, IntPtr pvPermission, uint cbPermission) + { + throw new NotImplementedException (); + } + + public void SetRVA (uint md, uint ulRVA) + { + throw new NotImplementedException (); + } + + public uint GetTokenFromSig (IntPtr pvSig, uint cbSig) + { + throw new NotImplementedException (); + } + + public uint DefineModuleRef (string szName) + { + throw new NotImplementedException (); + } + + public void SetParent (uint mr, uint tk) + { + throw new NotImplementedException (); + } + + public uint GetTokenFromTypeSpec (IntPtr pvSig, uint cbSig) + { + throw new NotImplementedException (); + } + + public void SaveToMemory (IntPtr pbData, uint cbData) + { + throw new NotImplementedException (); + } + + public uint DefineUserString (string szString, uint cchString) + { + throw new NotImplementedException (); + } + + public void DeleteToken (uint tkObj) + { + throw new NotImplementedException (); + } + + public void SetMethodProps (uint md, uint dwMethodFlags, uint ulCodeRVA, uint dwImplFlags) + { + throw new NotImplementedException (); + } + + public void SetTypeDefProps (uint td, uint dwTypeDefFlags, uint tkExtends, IntPtr rtkImplements) + { + throw new NotImplementedException (); + } + + public void SetEventProps (uint ev, uint dwEventFlags, uint tkEventType, uint mdAddOn, uint mdRemoveOn, uint mdFire, IntPtr rmdOtherMethods) + { + throw new NotImplementedException (); + } + + public uint SetPermissionSetProps (uint tk, uint dwAction, IntPtr pvPermission, uint cbPermission) + { + throw new NotImplementedException (); + } + + public void DefinePinvokeMap (uint tk, uint dwMappingFlags, string szImportName, uint mrImportDLL) + { + throw new NotImplementedException (); + } + + public void SetPinvokeMap (uint tk, uint dwMappingFlags, string szImportName, uint mrImportDLL) + { + throw new NotImplementedException (); + } + + public void DeletePinvokeMap (uint tk) + { + throw new NotImplementedException (); + } + + public uint DefineCustomAttribute (uint tkObj, uint tkType, IntPtr pCustomAttribute, uint cbCustomAttribute) + { + throw new NotImplementedException (); + } + + public void SetCustomAttributeValue (uint pcv, IntPtr pCustomAttribute, uint cbCustomAttribute) + { + throw new NotImplementedException (); + } + + public uint DefineField (uint td, string szName, uint dwFieldFlags, IntPtr pvSigBlob, uint cbSigBlob, uint dwCPlusTypeFlag, IntPtr pValue, uint cchValue) + { + throw new NotImplementedException (); + } + + public uint DefineProperty (uint td, string szProperty, uint dwPropFlags, IntPtr pvSig, uint cbSig, uint dwCPlusTypeFlag, IntPtr pValue, uint cchValue, uint mdSetter, uint mdGetter, IntPtr rmdOtherMethods) + { + throw new NotImplementedException (); + } + + public uint DefineParam (uint md, uint ulParamSeq, string szName, uint dwParamFlags, uint dwCPlusTypeFlag, IntPtr pValue, uint cchValue) + { + throw new NotImplementedException (); + } + + public void SetFieldProps (uint fd, uint dwFieldFlags, uint dwCPlusTypeFlag, IntPtr pValue, uint cchValue) + { + throw new NotImplementedException (); + } + + public void SetPropertyProps (uint pr, uint dwPropFlags, uint dwCPlusTypeFlag, IntPtr pValue, uint cchValue, uint mdSetter, uint mdGetter, IntPtr rmdOtherMethods) + { + throw new NotImplementedException (); + } + + public void SetParamProps (uint pd, string szName, uint dwParamFlags, uint dwCPlusTypeFlag, IntPtr pValue, uint cchValue) + { + throw new NotImplementedException (); + } + + public uint DefineSecurityAttributeSet (uint tkObj, IntPtr rSecAttrs, uint cSecAttrs) + { + throw new NotImplementedException (); + } + + public void ApplyEditAndContinue (object pImport) + { + throw new NotImplementedException (); + } + + public uint TranslateSigWithScope (IntPtr pAssemImport, IntPtr pbHashValue, uint cbHashValue, IMetaDataImport import, IntPtr pbSigBlob, uint cbSigBlob, IntPtr pAssemEmit, IMetaDataEmit emit, IntPtr pvTranslatedSig, uint cbTranslatedSigMax) + { + throw new NotImplementedException (); + } + + public void SetMethodImplFlags (uint md, uint dwImplFlags) + { + throw new NotImplementedException (); + } + + public void SetFieldRVA (uint fd, uint ulRVA) + { + throw new NotImplementedException (); + } + + public void Merge (IMetaDataImport pImport, IntPtr pHostMapToken, object pHandler) + { + throw new NotImplementedException (); + } + + public void MergeEnd () + { + throw new NotImplementedException (); + } + + public void CloseEnum (uint hEnum) + { + throw new NotImplementedException (); + } + + public uint CountEnum (uint hEnum) + { + throw new NotImplementedException (); + } + + public void ResetEnum (uint hEnum, uint ulPos) + { + throw new NotImplementedException (); + } + + public uint EnumTypeDefs (ref uint phEnum, uint[] rTypeDefs, uint cMax) + { + throw new NotImplementedException (); + } + + public uint EnumInterfaceImpls (ref uint phEnum, uint td, uint[] rImpls, uint cMax) + { + throw new NotImplementedException (); + } + + public uint EnumTypeRefs (ref uint phEnum, uint[] rTypeRefs, uint cMax) + { + throw new NotImplementedException (); + } + + public uint FindTypeDefByName (string szTypeDef, uint tkEnclosingClass) + { + throw new NotImplementedException (); + } + + public Guid GetScopeProps (StringBuilder szName, uint cchName, out uint pchName) + { + throw new NotImplementedException (); + } + + public uint GetModuleFromScope () + { + throw new NotImplementedException (); + } + + public uint GetTypeDefProps (uint td, IntPtr szTypeDef, uint cchTypeDef, out uint pchTypeDef, ref uint pdwTypeDefFlags) + { + pchTypeDef = 0; + return td; + } + + public uint GetInterfaceImplProps (uint iiImpl, out uint pClass) + { + throw new NotImplementedException (); + } + + public uint GetTypeRefProps (uint tr, out uint ptkResolutionScope, StringBuilder szName, uint cchName) + { + throw new NotImplementedException (); + } + + public uint ResolveTypeRef (uint tr, ref Guid riid, out object ppIScope) + { + throw new NotImplementedException (); + } + + public uint EnumMembers (ref uint phEnum, uint cl, uint[] rMembers, uint cMax) + { + throw new NotImplementedException (); + } + + public uint EnumMembersWithName (ref uint phEnum, uint cl, string szName, uint[] rMembers, uint cMax) + { + throw new NotImplementedException (); + } + + public uint EnumMethods (ref uint phEnum, uint cl, IntPtr rMethods, uint cMax) + { + throw new NotImplementedException (); + } + + public uint EnumMethodsWithName (ref uint phEnum, uint cl, string szName, uint[] rMethods, uint cMax) + { + throw new NotImplementedException (); + } + + public uint EnumFields (ref uint phEnum, uint cl, IntPtr rFields, uint cMax) + { + throw new NotImplementedException (); + } + + public uint EnumFieldsWithName (ref uint phEnum, uint cl, string szName, uint[] rFields, uint cMax) + { + throw new NotImplementedException (); + } + + public uint EnumParams (ref uint phEnum, uint mb, uint[] rParams, uint cMax) + { + throw new NotImplementedException (); + } + + public uint EnumMemberRefs (ref uint phEnum, uint tkParent, uint[] rMemberRefs, uint cMax) + { + throw new NotImplementedException (); + } + + public uint EnumMethodImpls (ref uint phEnum, uint td, uint[] rMethodBody, uint[] rMethodDecl, uint cMax) + { + throw new NotImplementedException (); + } + + public uint EnumPermissionSets (ref uint phEnum, uint tk, uint dwActions, uint[] rPermission, uint cMax) + { + throw new NotImplementedException (); + } + + public uint FindMember (uint td, string szName, byte[] pvSigBlob, uint cbSigBlob) + { + throw new NotImplementedException (); + } + + public uint FindMethod (uint td, string szName, byte[] pvSigBlob, uint cbSigBlob) + { + throw new NotImplementedException (); + } + + public uint FindField (uint td, string szName, byte[] pvSigBlob, uint cbSigBlob) + { + throw new NotImplementedException (); + } + + public uint FindMemberRef (uint td, string szName, byte[] pvSigBlob, uint cbSigBlob) + { + throw new NotImplementedException (); + } + + public uint GetMethodProps (uint mb, out uint pClass, IntPtr szMethod, uint cchMethod, out uint pchMethod, IntPtr pdwAttr, IntPtr ppvSigBlob, IntPtr pcbSigBlob, IntPtr pulCodeRVA) + { + pClass = 0; + pchMethod = 0; + return mb; + } + + public uint GetMemberRefProps (uint mr, ref uint ptk, StringBuilder szMember, uint cchMember, out uint pchMember, out IntPtr ppvSigBlob) + { + throw new NotImplementedException (); + } + + public uint EnumProperties (ref uint phEnum, uint td, IntPtr rProperties, uint cMax) + { + throw new NotImplementedException (); + } + + public uint EnumEvents (ref uint phEnum, uint td, IntPtr rEvents, uint cMax) + { + throw new NotImplementedException (); + } + + public uint GetEventProps (uint ev, out uint pClass, StringBuilder szEvent, uint cchEvent, out uint pchEvent, out uint pdwEventFlags, out uint ptkEventType, out uint pmdAddOn, out uint pmdRemoveOn, out uint pmdFire, uint[] rmdOtherMethod, uint cMax) + { + throw new NotImplementedException (); + } + + public uint EnumMethodSemantics (ref uint phEnum, uint mb, uint[] rEventProp, uint cMax) + { + throw new NotImplementedException (); + } + + public uint GetMethodSemantics (uint mb, uint tkEventProp) + { + throw new NotImplementedException (); + } + + public uint GetClassLayout (uint td, out uint pdwPackSize, IntPtr rFieldOffset, uint cMax, out uint pcFieldOffset) + { + throw new NotImplementedException (); + } + + public uint GetFieldMarshal (uint tk, out IntPtr ppvNativeType) + { + throw new NotImplementedException (); + } + + public uint GetRVA (uint tk, out uint pulCodeRVA) + { + throw new NotImplementedException (); + } + + public uint GetPermissionSetProps (uint pm, out uint pdwAction, out IntPtr ppvPermission) + { + throw new NotImplementedException (); + } + + public uint GetSigFromToken (uint mdSig, out IntPtr ppvSig) + { + throw new NotImplementedException (); + } + + public uint GetModuleRefProps (uint mur, StringBuilder szName, uint cchName) + { + throw new NotImplementedException (); + } + + public uint EnumModuleRefs (ref uint phEnum, uint[] rModuleRefs, uint cmax) + { + throw new NotImplementedException (); + } + + public uint GetTypeSpecFromToken (uint typespec, out IntPtr ppvSig) + { + throw new NotImplementedException (); + } + + public uint GetNameFromToken (uint tk) + { + throw new NotImplementedException (); + } + + public uint EnumUnresolvedMethods (ref uint phEnum, uint[] rMethods, uint cMax) + { + throw new NotImplementedException (); + } + + public uint GetUserString (uint stk, StringBuilder szString, uint cchString) + { + throw new NotImplementedException (); + } + + public uint GetPinvokeMap (uint tk, out uint pdwMappingFlags, StringBuilder szImportName, uint cchImportName, out uint pchImportName) + { + throw new NotImplementedException (); + } + + public uint EnumSignatures (ref uint phEnum, uint[] rSignatures, uint cmax) + { + throw new NotImplementedException (); + } + + public uint EnumTypeSpecs (ref uint phEnum, uint[] rTypeSpecs, uint cmax) + { + throw new NotImplementedException (); + } + + public uint EnumUserStrings (ref uint phEnum, uint[] rStrings, uint cmax) + { + throw new NotImplementedException (); + } + + public int GetParamForMethodIndex (uint md, uint ulParamSeq, out uint pParam) + { + throw new NotImplementedException (); + } + + public uint EnumCustomAttributes (ref uint phEnum, uint tk, uint tkType, uint[] rCustomAttributes, uint cMax) + { + throw new NotImplementedException (); + } + + public uint GetCustomAttributeProps (uint cv, out uint ptkObj, out uint ptkType, out IntPtr ppBlob) + { + throw new NotImplementedException (); + } + + public uint FindTypeRef (uint tkResolutionScope, string szName) + { + throw new NotImplementedException (); + } + + public uint GetMemberProps (uint mb, out uint pClass, StringBuilder szMember, uint cchMember, out uint pchMember, out uint pdwAttr, out IntPtr ppvSigBlob, out uint pcbSigBlob, out uint pulCodeRVA, out uint pdwImplFlags, out uint pdwCPlusTypeFlag, out IntPtr ppValue) + { + throw new NotImplementedException (); + } + + public uint GetFieldProps (uint mb, out uint pClass, StringBuilder szField, uint cchField, out uint pchField, out uint pdwAttr, out IntPtr ppvSigBlob, out uint pcbSigBlob, out uint pdwCPlusTypeFlag, out IntPtr ppValue) + { + throw new NotImplementedException (); + } + + public uint GetPropertyProps (uint prop, out uint pClass, StringBuilder szProperty, uint cchProperty, out uint pchProperty, out uint pdwPropFlags, out IntPtr ppvSig, out uint pbSig, out uint pdwCPlusTypeFlag, out IntPtr ppDefaultValue, out uint pcchDefaultValue, out uint pmdSetter, out uint pmdGetter, uint[] rmdOtherMethod, uint cMax) + { + throw new NotImplementedException (); + } + + public uint GetParamProps (uint tk, out uint pmd, out uint pulSequence, StringBuilder szName, uint cchName, out uint pchName, out uint pdwAttr, out uint pdwCPlusTypeFlag, out IntPtr ppValue) + { + throw new NotImplementedException (); + } + + public uint GetCustomAttributeByName (uint tkObj, string szName, out IntPtr ppData) + { + throw new NotImplementedException (); + } + + public bool IsValidToken (uint tk) + { + throw new NotImplementedException (); + } + + public uint GetNestedClassProps (uint tdNestedClass) + { + throw new NotImplementedException (); + } + + public uint GetNativeCallConvFromSig (IntPtr pvSig, uint cbSig) + { + throw new NotImplementedException (); + } + + public int IsGlobal (uint pd) + { + throw new NotImplementedException (); + } + } +} + +#endif diff --git a/symbols/pdb/Mono.Cecil.Pdb/PdbHelper.cs b/symbols/pdb/Mono.Cecil.Pdb/PdbHelper.cs new file mode 100644 index 000000000..0820b17f6 --- /dev/null +++ b/symbols/pdb/Mono.Cecil.Pdb/PdbHelper.cs @@ -0,0 +1,205 @@ +// +// PdbHelper.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Generic; +using System.IO; + +using Mono.Cecil.Cil; + +namespace Mono.Cecil.Pdb { + + class PdbHelper { + +#if !READ_ONLY + public static SymWriter CreateWriter (ModuleDefinition module, string pdb) + { + var writer = new SymWriter (); + + if (File.Exists (pdb)) + File.Delete (pdb); + + writer.Initialize (new ModuleMetadata (module), pdb, true); + + return writer; + } +#endif + + public static string GetPdbFileName (string assemblyFileName) + { + return Path.ChangeExtension (assemblyFileName, ".pdb"); + } + } + + public class PdbReaderProvider : ISymbolReaderProvider { + + public ISymbolReader GetSymbolReader (ModuleDefinition module, string fileName) + { + return new PdbReader (File.OpenRead (PdbHelper.GetPdbFileName (fileName))); + } + + public ISymbolReader GetSymbolReader (ModuleDefinition module, Stream symbolStream) + { + throw new NotImplementedException (); + } + } + +#if !READ_ONLY + + public class PdbWriterProvider : ISymbolWriterProvider { + + public ISymbolWriter GetSymbolWriter (ModuleDefinition module, string fileName) + { + return new PdbWriter (module, PdbHelper.CreateWriter (module, PdbHelper.GetPdbFileName (fileName))); + } + + public ISymbolWriter GetSymbolWriter (ModuleDefinition module, Stream symbolStream) + { + throw new NotImplementedException (); + } + } + +#endif + + static class GuidMapping { + + static readonly Dictionary guid_language = new Dictionary (); + static readonly Dictionary language_guid = new Dictionary (); + + static GuidMapping () + { + AddMapping (DocumentLanguage.C, new Guid (0x63a08714, 0xfc37, 0x11d2, 0x90, 0x4c, 0x0, 0xc0, 0x4f, 0xa3, 0x02, 0xa1)); + AddMapping (DocumentLanguage.Cpp, new Guid (0x3a12d0b7, 0xc26c, 0x11d0, 0xb4, 0x42, 0x0, 0xa0, 0x24, 0x4a, 0x1d, 0xd2)); + AddMapping (DocumentLanguage.CSharp, new Guid (0x3f5162f8, 0x07c6, 0x11d3, 0x90, 0x53, 0x0, 0xc0, 0x4f, 0xa3, 0x02, 0xa1)); + AddMapping (DocumentLanguage.Basic, new Guid (0x3a12d0b8, 0xc26c, 0x11d0, 0xb4, 0x42, 0x0, 0xa0, 0x24, 0x4a, 0x1d, 0xd2)); + AddMapping (DocumentLanguage.Java, new Guid (0x3a12d0b4, 0xc26c, 0x11d0, 0xb4, 0x42, 0x0, 0xa0, 0x24, 0x4a, 0x1d, 0xd2)); + AddMapping (DocumentLanguage.Cobol, new Guid (0xaf046cd1, 0xd0e1, 0x11d2, 0x97, 0x7c, 0x0, 0xa0, 0xc9, 0xb4, 0xd5, 0xc)); + AddMapping (DocumentLanguage.Pascal, new Guid (0xaf046cd2, 0xd0e1, 0x11d2, 0x97, 0x7c, 0x0, 0xa0, 0xc9, 0xb4, 0xd5, 0xc)); + AddMapping (DocumentLanguage.Cil, new Guid (0xaf046cd3, 0xd0e1, 0x11d2, 0x97, 0x7c, 0x0, 0xa0, 0xc9, 0xb4, 0xd5, 0xc)); + AddMapping (DocumentLanguage.JScript, new Guid (0x3a12d0b6, 0xc26c, 0x11d0, 0xb4, 0x42, 0x0, 0xa0, 0x24, 0x4a, 0x1d, 0xd2)); + AddMapping (DocumentLanguage.Smc, new Guid (0xd9b9f7b, 0x6611, 0x11d3, 0xbd, 0x2a, 0x0, 0x0, 0xf8, 0x8, 0x49, 0xbd)); + AddMapping (DocumentLanguage.MCpp, new Guid (0x4b35fde8, 0x07c6, 0x11d3, 0x90, 0x53, 0x0, 0xc0, 0x4f, 0xa3, 0x02, 0xa1)); + } + + static void AddMapping (DocumentLanguage language, Guid guid) + { + guid_language.Add (guid, language); + language_guid.Add (language, guid); + } + + static readonly Guid type_text = new Guid (0x5a869d0b, 0x6611, 0x11d3, 0xbd, 0x2a, 0x00, 0x00, 0xf8, 0x08, 0x49, 0xbd); + + public static DocumentType ToType (this Guid guid) + { + if (guid == type_text) + return DocumentType.Text; + + return DocumentType.Other; + } + + public static Guid ToGuid (this DocumentType type) + { + if (type == DocumentType.Text) + return type_text; + + return new Guid (); + } + + static readonly Guid hash_md5 = new Guid (0x406ea660, 0x64cf, 0x4c82, 0xb6, 0xf0, 0x42, 0xd4, 0x81, 0x72, 0xa7, 0x99); + static readonly Guid hash_sha1 = new Guid (0xff1816ec, 0xaa5e, 0x4d10, 0x87, 0xf7, 0x6f, 0x49, 0x63, 0x83, 0x34, 0x60); + + public static DocumentHashAlgorithm ToHashAlgorithm (this Guid guid) + { + if (guid == hash_md5) + return DocumentHashAlgorithm.MD5; + + if (guid == hash_sha1) + return DocumentHashAlgorithm.SHA1; + + return DocumentHashAlgorithm.None; + } + + public static Guid ToGuid (this DocumentHashAlgorithm hash_algo) + { + if (hash_algo == DocumentHashAlgorithm.MD5) + return hash_md5; + + if (hash_algo == DocumentHashAlgorithm.SHA1) + return hash_sha1; + + return new Guid (); + } + + public static DocumentLanguage ToLanguage (this Guid guid) + { + DocumentLanguage language; + if (!guid_language.TryGetValue (guid, out language)) + return DocumentLanguage.Other; + + return language; + } + + public static Guid ToGuid (this DocumentLanguage language) + { + Guid guid; + if (!language_guid.TryGetValue (language, out guid)) + return new Guid (); + + return guid; + } + + static readonly Guid vendor_ms = new Guid (0x994b45c4, 0xe6e9, 0x11d2, 0x90, 0x3f, 0x00, 0xc0, 0x4f, 0xa3, 0x02, 0xa1); + + public static DocumentLanguageVendor ToVendor (this Guid guid) + { + if (guid == vendor_ms) + return DocumentLanguageVendor.Microsoft; + + return DocumentLanguageVendor.Other; + } + + public static Guid ToGuid (this DocumentLanguageVendor vendor) + { + if (vendor == DocumentLanguageVendor.Microsoft) + return vendor_ms; + + return new Guid (); + } + } +} + +#if !NET_3_5 && !NET_4_0 + +namespace System.Runtime.CompilerServices { + + [AttributeUsage (AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Assembly)] + sealed class ExtensionAttribute : Attribute { + } +} + +#endif diff --git a/symbols/pdb/Mono.Cecil.Pdb/PdbReader.cs b/symbols/pdb/Mono.Cecil.Pdb/PdbReader.cs new file mode 100644 index 000000000..59bfa1bac --- /dev/null +++ b/symbols/pdb/Mono.Cecil.Pdb/PdbReader.cs @@ -0,0 +1,282 @@ +// +// PdbReader.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Generic; +using System.IO; + +using Microsoft.Cci.Pdb; + +using Mono.Cecil.Cil; + +namespace Mono.Cecil.Pdb { + + public class PdbReader : ISymbolReader { + + int age; + Guid guid; + + readonly Stream pdb_file; + readonly Dictionary documents = new Dictionary (); + readonly Dictionary functions = new Dictionary (); + + internal PdbReader (Stream file) + { + this.pdb_file = file; + } + + /* + uint Magic = 0x53445352; + Guid Signature; + uint Age; + string FileName; + */ + + public bool ProcessDebugHeader (ImageDebugDirectory directory, byte [] header) + { + if (header.Length < 24) + return false; + + var magic = ReadInt32 (header, 0); + if (magic != 0x53445352) + return false; + + var guid_bytes = new byte [16]; + Buffer.BlockCopy (header, 4, guid_bytes, 0, 16); + + this.guid = new Guid (guid_bytes); + this.age = ReadInt32 (header, 20); + + return PopulateFunctions (); + } + + static int ReadInt32 (byte [] bytes, int start) + { + return (bytes [start] + | (bytes [start + 1] << 8) + | (bytes [start + 2] << 16) + | (bytes [start + 3] << 24)); + } + + bool PopulateFunctions () + { + using (pdb_file) { + int age; + Guid guid; + var funcs = PdbFile.LoadFunctions (pdb_file, true, out age, out guid); + + if (this.age != 0) { + if (this.age != age) + return false; + if (this.guid != guid) + return false; + } + + foreach (PdbFunction function in funcs) + functions.Add (function.token, function); + } + + return true; + } + + public void Read (MethodBody body, InstructionMapper mapper) + { + var method_token = body.Method.MetadataToken; + + PdbFunction function; + if (!functions.TryGetValue (method_token.ToUInt32 (), out function)) + return; + + ReadSequencePoints (function, mapper); + ReadScopeAndLocals (function.scopes, null, body, mapper); + } + + static void ReadScopeAndLocals (PdbScope [] scopes, Scope parent, MethodBody body, InstructionMapper mapper) + { + foreach (PdbScope scope in scopes) + ReadScopeAndLocals (scope, parent, body, mapper); + + CreateRootScope (body); + } + + static void CreateRootScope (MethodBody body) + { + if (!body.HasVariables) + return; + + var instructions = body.Instructions; + + var root = new Scope (); + root.Start = instructions [0]; + root.End = instructions [instructions.Count - 1]; + + var variables = body.Variables; + for (int i = 0; i < variables.Count; i++) + root.Variables.Add (variables [i]); + + body.Scope = root; + } + + static void ReadScopeAndLocals (PdbScope scope, Scope parent, MethodBody body, InstructionMapper mapper) + { + //Scope s = new Scope (); + //s.Start = GetInstruction (body, instructions, (int) scope.address); + //s.End = GetInstruction (body, instructions, (int) scope.length - 1); + + //if (parent != null) + // parent.Scopes.Add (s); + //else + // body.Scopes.Add (s); + + if (scope == null) + return; + + foreach (PdbSlot slot in scope.slots) { + int index = (int) slot.slot; + if (index < 0 || index >= body.Variables.Count) + continue; + + VariableDefinition variable = body.Variables [index]; + variable.Name = slot.name; + + //s.Variables.Add (variable); + } + + ReadScopeAndLocals (scope.scopes, null /* s */, body, mapper); + } + + void ReadSequencePoints (PdbFunction function, InstructionMapper mapper) + { + if (function.lines == null) + return; + + foreach (PdbLines lines in function.lines) + ReadLines (lines, mapper); + } + + void ReadLines (PdbLines lines, InstructionMapper mapper) + { + var document = GetDocument (lines.file); + + foreach (var line in lines.lines) + ReadLine (line, document, mapper); + } + + static void ReadLine (PdbLine line, Document document, InstructionMapper mapper) + { + var instruction = mapper ((int) line.offset); + if (instruction == null) + return; + + var sequence_point = new SequencePoint (document); + sequence_point.StartLine = (int) line.lineBegin; + sequence_point.StartColumn = (int) line.colBegin; + sequence_point.EndLine = (int) line.lineEnd; + sequence_point.EndColumn = (int) line.colEnd; + + instruction.SequencePoint = sequence_point; + } + + Document GetDocument (PdbSource source) + { + string name = source.name; + Document document; + if (documents.TryGetValue (name, out document)) + return document; + + document = new Document (name) { + Language = source.language.ToLanguage (), + LanguageVendor = source.vendor.ToVendor (), + Type = source.doctype.ToType (), + }; + documents.Add (name, document); + return document; + } + + public void Read (MethodSymbols symbols) + { + PdbFunction function; + if (!functions.TryGetValue (symbols.MethodToken.ToUInt32 (), out function)) + return; + + ReadSequencePoints (function, symbols); + ReadLocals (function.scopes, symbols); + } + + void ReadLocals (PdbScope [] scopes, MethodSymbols symbols) + { + foreach (var scope in scopes) + ReadLocals (scope, symbols); + } + + void ReadLocals (PdbScope scope, MethodSymbols symbols) + { + if (scope == null) + return; + + foreach (var slot in scope.slots) { + int index = (int) slot.slot; + if (index < 0 || index >= symbols.Variables.Count) + continue; + + var variable = symbols.Variables [index]; + variable.Name = slot.name; + } + + ReadLocals (scope.scopes, symbols); + } + + void ReadSequencePoints (PdbFunction function, MethodSymbols symbols) + { + if (function.lines == null) + return; + + foreach (PdbLines lines in function.lines) + ReadLines (lines, symbols); + } + + void ReadLines (PdbLines lines, MethodSymbols symbols) + { + for (int i = 0; i < lines.lines.Length; i++) { + var line = lines.lines [i]; + + symbols.Instructions.Add (new InstructionSymbol ((int) line.offset, new SequencePoint (GetDocument (lines.file)) { + StartLine = (int) line.lineBegin, + StartColumn = (int) line.colBegin, + EndLine = (int) line.lineEnd, + EndColumn = (int) line.colEnd, + })); + } + } + + public void Dispose () + { + pdb_file.Close (); + } + } +} diff --git a/symbols/pdb/Mono.Cecil.Pdb/PdbWriter.cs b/symbols/pdb/Mono.Cecil.Pdb/PdbWriter.cs new file mode 100644 index 000000000..24d62078e --- /dev/null +++ b/symbols/pdb/Mono.Cecil.Pdb/PdbWriter.cs @@ -0,0 +1,222 @@ +// +// PdbWriter.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2010 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Generic; +using System.Diagnostics.SymbolStore; + +using Mono.Cecil.Cil; +using Mono.Collections.Generic; + +#if !READ_ONLY + +namespace Mono.Cecil.Pdb { + + public class PdbWriter : Cil.ISymbolWriter { + + readonly ModuleDefinition module; + readonly SymWriter writer; + readonly Dictionary documents; + + internal PdbWriter (ModuleDefinition module, SymWriter writer) + { + this.module = module; + this.writer = writer; + this.documents = new Dictionary (); + } + + public bool GetDebugHeader (out ImageDebugDirectory directory, out byte [] header) + { + header = writer.GetDebugInfo (out directory); + return true; + } + + public void Write (MethodBody body) + { + var method_token = body.Method.MetadataToken; + var sym_token = new SymbolToken (method_token.ToInt32 ()); + + var instructions = CollectInstructions (body); + if (instructions.Count == 0) + return; + + var start_offset = 0; + var end_offset = body.CodeSize; + + writer.OpenMethod (sym_token); + writer.OpenScope (start_offset); + + DefineSequencePoints (instructions); + DefineVariables (body, start_offset, end_offset); + + writer.CloseScope (end_offset); + writer.CloseMethod (); + } + + Collection CollectInstructions (MethodBody body) + { + var collection = new Collection (); + var instructions = body.Instructions; + + for (int i = 0; i < instructions.Count; i++) { + var instruction = instructions [i]; + var sequence_point = instruction.SequencePoint; + if (sequence_point == null) + continue; + + GetDocument (sequence_point.Document); + collection.Add (instruction); + } + + return collection; + } + + void DefineVariables (MethodBody body, int start_offset, int end_offset) + { + if (!body.HasVariables) + return; + + var sym_token = new SymbolToken (body.LocalVarToken.ToInt32 ()); + + var variables = body.Variables; + for (int i = 0; i < variables.Count; i++) { + var variable = variables [i]; + CreateLocalVariable (variable, sym_token, start_offset, end_offset); + } + } + + void DefineSequencePoints (Collection instructions) + { + for (int i = 0; i < instructions.Count; i++) { + var instruction = instructions [i]; + var sequence_point = instruction.SequencePoint; + + writer.DefineSequencePoints ( + GetDocument (sequence_point.Document), + new [] { instruction.Offset }, + new [] { sequence_point.StartLine }, + new [] { sequence_point.StartColumn }, + new [] { sequence_point.EndLine }, + new [] { sequence_point.EndColumn }); + } + } + + void CreateLocalVariable (VariableDefinition variable, SymbolToken local_var_token, int start_offset, int end_offset) + { + writer.DefineLocalVariable2 ( + variable.Name, + 0, + local_var_token, + SymAddressKind.ILOffset, + variable.Index, + 0, + 0, + start_offset, + end_offset); + } + + SymDocumentWriter GetDocument (Document document) + { + if (document == null) + return null; + + SymDocumentWriter doc_writer; + if (documents.TryGetValue (document.Url, out doc_writer)) + return doc_writer; + + doc_writer = writer.DefineDocument ( + document.Url, + document.Language.ToGuid (), + document.LanguageVendor.ToGuid (), + document.Type.ToGuid ()); + + documents [document.Url] = doc_writer; + return doc_writer; + } + + public void Write (MethodSymbols symbols) + { + var sym_token = new SymbolToken (symbols.MethodToken.ToInt32 ()); + + var start_offset = 0; + var end_offset = symbols.CodeSize; + + writer.OpenMethod (sym_token); + writer.OpenScope (start_offset); + + DefineSequencePoints (symbols); + DefineVariables (symbols, start_offset, end_offset); + + writer.CloseScope (end_offset); + writer.CloseMethod (); + } + + void DefineSequencePoints (MethodSymbols symbols) + { + var instructions = symbols.instructions; + + for (int i = 0; i < instructions.Count; i++) { + var instruction = instructions [i]; + var sequence_point = instruction.SequencePoint; + + writer.DefineSequencePoints ( + GetDocument (sequence_point.Document), + new [] { instruction.Offset }, + new [] { sequence_point.StartLine }, + new [] { sequence_point.StartColumn }, + new [] { sequence_point.EndLine }, + new [] { sequence_point.EndColumn }); + } + } + + void DefineVariables (MethodSymbols symbols, int start_offset, int end_offset) + { + if (!symbols.HasVariables) + return; + + var sym_token = new SymbolToken (symbols.LocalVarToken.ToInt32 ()); + + var variables = symbols.Variables; + for (int i = 0; i < variables.Count; i++) { + var variable = variables [i]; + CreateLocalVariable (variable, sym_token, start_offset, end_offset); + } + } + + public void Dispose () + { + var entry_point = module.EntryPoint; + if (entry_point != null) + writer.SetUserEntryPoint (new SymbolToken (entry_point.MetadataToken.ToInt32 ())); + + writer.Close (); + } + } +} + +#endif diff --git a/symbols/pdb/Mono.Cecil.Pdb/SymDocumentWriter.cs b/symbols/pdb/Mono.Cecil.Pdb/SymDocumentWriter.cs new file mode 100644 index 000000000..34918dc63 --- /dev/null +++ b/symbols/pdb/Mono.Cecil.Pdb/SymDocumentWriter.cs @@ -0,0 +1,51 @@ +// +// SymDocumentWriter.cs +// +// Author: +// Juerg Billeter (j@bitron.ch) +// +// (C) 2008 Juerg Billeter +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +#if !READ_ONLY + +namespace Mono.Cecil.Pdb +{ + internal class SymDocumentWriter + { + readonly ISymUnmanagedDocumentWriter m_unmanagedDocumentWriter; + + public SymDocumentWriter (ISymUnmanagedDocumentWriter unmanagedDocumentWriter) + { + m_unmanagedDocumentWriter = unmanagedDocumentWriter; + } + + public ISymUnmanagedDocumentWriter GetUnmanaged () + { + return m_unmanagedDocumentWriter; + } + } +} + +#endif diff --git a/symbols/pdb/Mono.Cecil.Pdb/SymWriter.cs b/symbols/pdb/Mono.Cecil.Pdb/SymWriter.cs new file mode 100644 index 000000000..678942a34 --- /dev/null +++ b/symbols/pdb/Mono.Cecil.Pdb/SymWriter.cs @@ -0,0 +1,170 @@ +// +// SymWriter.cs +// +// Author: +// Juerg Billeter (j@bitron.ch) +// +// (C) 2008 Juerg Billeter +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Generic; +using System.Diagnostics.SymbolStore; +using System.Runtime.InteropServices; + +using Mono.Cecil.Cil; +using Mono.Collections.Generic; + +#if !READ_ONLY + +namespace Mono.Cecil.Pdb +{ + internal class SymWriter + { + [DllImport("ole32.dll")] + static extern int CoCreateInstance ( + [In] ref Guid rclsid, + [In, MarshalAs (UnmanagedType.IUnknown)] object pUnkOuter, + [In] uint dwClsContext, + [In] ref Guid riid, + [Out, MarshalAs (UnmanagedType.Interface)] out object ppv); + + static Guid s_symUnmangedWriterIID = new Guid("0b97726e-9e6d-4f05-9a26-424022093caa"); + static Guid s_CorSymWriter_SxS_ClassID = new Guid ("108296c1-281e-11d3-bd22-0000f80849bd"); + + readonly ISymUnmanagedWriter2 m_writer; + readonly Collection documents; + + public SymWriter () + { + object objWriter; + CoCreateInstance (ref s_CorSymWriter_SxS_ClassID, null, 1, ref s_symUnmangedWriterIID, out objWriter); + + m_writer = (ISymUnmanagedWriter2) objWriter; + documents = new Collection (); + } + + public byte[] GetDebugInfo (out ImageDebugDirectory idd) + { + int size; + + // get size of debug info + m_writer.GetDebugInfo (out idd, 0, out size, null); + + byte[] debug_info = new byte[size]; + m_writer.GetDebugInfo (out idd, size, out size, debug_info); + + return debug_info; + } + + public void DefineLocalVariable2 ( + string name, + FieldAttributes attributes, + SymbolToken sigToken, + SymAddressKind addrKind, + int addr1, + int addr2, + int addr3, + int startOffset, + int endOffset) + { + m_writer.DefineLocalVariable2 (name, (int)attributes, sigToken, (int)addrKind, addr1, addr2, addr3, startOffset, endOffset); + } + + public void Close () + { + m_writer.Close (); + Marshal.ReleaseComObject (m_writer); + + foreach (var document in documents) + Marshal.ReleaseComObject (document); + } + + public void CloseMethod () + { + m_writer.CloseMethod (); + } + + public void CloseNamespace () + { + m_writer.CloseNamespace (); + } + + public void CloseScope (int endOffset) + { + m_writer.CloseScope (endOffset); + } + + public SymDocumentWriter DefineDocument (string url, Guid language, Guid languageVendor, Guid documentType) + { + ISymUnmanagedDocumentWriter unmanagedDocumentWriter; + m_writer.DefineDocument (url, ref language, ref languageVendor, ref documentType, out unmanagedDocumentWriter); + + documents.Add (unmanagedDocumentWriter); + return new SymDocumentWriter (unmanagedDocumentWriter); + } + + public void DefineParameter (string name, ParameterAttributes attributes, int sequence, SymAddressKind addrKind, int addr1, int addr2, int addr3) + { + throw new Exception ("The method or operation is not implemented."); + } + + public void DefineSequencePoints (SymDocumentWriter document, int[] offsets, int[] lines, int[] columns, int[] endLines, int[] endColumns) + { + m_writer.DefineSequencePoints (document.GetUnmanaged(), offsets.Length, offsets, lines, columns, endLines, endColumns); + } + + public void Initialize (object emitter, string filename, bool fFullBuild) + { + m_writer.Initialize (emitter, filename, null, fFullBuild); + } + + public void SetUserEntryPoint (SymbolToken method) + { + m_writer.SetUserEntryPoint (method); + } + + public void OpenMethod (SymbolToken method) + { + m_writer.OpenMethod (method); + } + + public void OpenNamespace (string name) + { + m_writer.OpenNamespace (name); + } + + public int OpenScope (int startOffset) + { + int result; + m_writer.OpenScope (startOffset, out result); + return result; + } + + public void UsingNamespace (string fullName) + { + m_writer.UsingNamespace (fullName); + } + } +} + +#endif diff --git a/symbols/pdb/Test/.gitignore b/symbols/pdb/Test/.gitignore new file mode 100644 index 000000000..17ff3483d --- /dev/null +++ b/symbols/pdb/Test/.gitignore @@ -0,0 +1,4 @@ +bin +obj +*.xml +*.user diff --git a/symbols/pdb/Test/Mono.Cecil.Pdb.Tests.csproj b/symbols/pdb/Test/Mono.Cecil.Pdb.Tests.csproj new file mode 100644 index 000000000..68fef1924 --- /dev/null +++ b/symbols/pdb/Test/Mono.Cecil.Pdb.Tests.csproj @@ -0,0 +1,120 @@ + + + + net_4_0_Debug + AnyCPU + 9.0.30729 + 2.0 + {29300103-CB76-4A1D-B6FD-FFD91C1EC8AA} + Library + Properties + Mono.Cecil.Pdb.Tests + Mono.Cecil.Pdb.Tests + 512 + + + true + full + false + bin\net_2_0_Debug\ + DEBUG;TRACE + prompt + 4 + v2.0 + + + pdbonly + true + bin\net_2_0_Release\ + TRACE + prompt + 4 + v2.0 + + + true + full + false + bin\net_3_5_Debug\ + DEBUG;TRACE;NET_3_5 + prompt + 4 + v3.5 + + + pdbonly + true + bin\net_3_5_Release\ + TRACE;NET_3_5 + prompt + 4 + v3.5 + + + true + full + false + bin\net_4_0_Debug\ + DEBUG;TRACE;NET_3_5;NET_4_0 + prompt + 4 + v4.0 + + + pdbonly + true + bin\net_4_0_Release\ + TRACE;NET_3_5;NET_4_0 + prompt + 4 + v4.0 + + + + + + + {D68133BD-1E63-496E-9EDE-4FBDBF77B486} + Mono.Cecil + + + {A47B1F49-A81A-43E8-BE6B-DD28AF2C4055} + Mono.Cecil.Tests + + + {63E6915C-7EA4-4D76-AB28-0D7191EEA626} + Mono.Cecil.Pdb + + + + + + + + + + + + + + False + ..\..\..\Test\libs\nunit-2.4.8\nunit.core.dll + + + False + ..\..\..\Test\libs\nunit-2.4.8\nunit.core.interfaces.dll + + + False + ..\..\..\Test\libs\nunit-2.4.8\nunit.framework.dll + + + + + \ No newline at end of file diff --git a/symbols/pdb/Test/Mono.Cecil.Tests/Addin.cs b/symbols/pdb/Test/Mono.Cecil.Tests/Addin.cs new file mode 100644 index 000000000..080f45eb3 --- /dev/null +++ b/symbols/pdb/Test/Mono.Cecil.Tests/Addin.cs @@ -0,0 +1,8 @@ +using NUnit.Core.Extensibility; + +namespace Mono.Cecil.Tests { + + [NUnitAddin] + public class CecilPdbAddin : CecilTestAddin { + } +} diff --git a/symbols/pdb/Test/Mono.Cecil.Tests/Linq.cs b/symbols/pdb/Test/Mono.Cecil.Tests/Linq.cs new file mode 100644 index 000000000..0950ce114 --- /dev/null +++ b/symbols/pdb/Test/Mono.Cecil.Tests/Linq.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; + +#if !NET_3_5 && !NET_4_0 + +namespace System { + + delegate TResult Func (T t); +} + +namespace System.Runtime.CompilerServices { + + [AttributeUsage (AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Assembly)] + sealed class ExtensionAttribute : Attribute { + } +} + +namespace System.Linq { + + static class Enumerable { + + public static IEnumerable Select (this IEnumerable self, Func selector) + { + foreach (var item in self) + yield return selector (item); + } + + public static IEnumerable Where (this IEnumerable self, Func predicate) + { + foreach (var item in self) + if (predicate (item)) + yield return item; + } + + public static T First (this IEnumerable self) + { + using (var enumerator = self.GetEnumerator ()) { + if (!enumerator.MoveNext ()) + throw new InvalidOperationException (); + + return enumerator.Current; + } + } + } +} + +#endif diff --git a/symbols/pdb/Test/Mono.Cecil.Tests/PdbTests.cs b/symbols/pdb/Test/Mono.Cecil.Tests/PdbTests.cs new file mode 100644 index 000000000..60d93a40c --- /dev/null +++ b/symbols/pdb/Test/Mono.Cecil.Tests/PdbTests.cs @@ -0,0 +1,139 @@ + +using System.IO; +using System.Linq; + +using Mono.Cecil.Cil; +using Mono.Cecil.Pdb; + +using NUnit.Framework; + +namespace Mono.Cecil.Tests { + + [TestFixture] + public class PdbTests : BaseTestFixture { + + [TestModule ("test.exe", SymbolReaderProvider = typeof (PdbReaderProvider), SymbolWriterProvider = typeof (PdbWriterProvider))] + public void Main (ModuleDefinition module) + { + var type = module.GetType ("Program"); + var main = type.GetMethod ("Main"); + + AssertCode (@" + .locals init (System.Int32 i, System.Int32 CS$1$0000, System.Boolean CS$4$0001) + .line 6,6:2,3 'c:\sources\cecil\symbols\Mono.Cecil.Pdb\Test\Resources\assemblies\test.cs' + IL_0000: nop + .line 7,7:8,18 'c:\sources\cecil\symbols\Mono.Cecil.Pdb\Test\Resources\assemblies\test.cs' + IL_0001: ldc.i4.0 + IL_0002: stloc.0 + .line 16707566,16707566:0,0 'c:\sources\cecil\symbols\Mono.Cecil.Pdb\Test\Resources\assemblies\test.cs' + IL_0003: br.s IL_0012 + .line 8,8:4,21 'c:\sources\cecil\symbols\Mono.Cecil.Pdb\Test\Resources\assemblies\test.cs' + IL_0005: ldarg.0 + IL_0006: ldloc.0 + IL_0007: ldelem.ref + IL_0008: call System.Void Program::Print(System.String) + IL_000d: nop + .line 7,7:36,39 'c:\sources\cecil\symbols\Mono.Cecil.Pdb\Test\Resources\assemblies\test.cs' + IL_000e: ldloc.0 + IL_000f: ldc.i4.1 + IL_0010: add + IL_0011: stloc.0 + .line 7,7:19,34 'c:\sources\cecil\symbols\Mono.Cecil.Pdb\Test\Resources\assemblies\test.cs' + IL_0012: ldloc.0 + IL_0013: ldarg.0 + IL_0014: ldlen + IL_0015: conv.i4 + IL_0016: clt + IL_0018: stloc.2 + .line 16707566,16707566:0,0 'c:\sources\cecil\symbols\Mono.Cecil.Pdb\Test\Resources\assemblies\test.cs' + IL_0019: ldloc.2 + IL_001a: brtrue.s IL_0005 + .line 10,10:3,12 'c:\sources\cecil\symbols\Mono.Cecil.Pdb\Test\Resources\assemblies\test.cs' + IL_001c: ldc.i4.0 + IL_001d: stloc.1 + IL_001e: br.s IL_0020 + .line 11,11:2,3 'c:\sources\cecil\symbols\Mono.Cecil.Pdb\Test\Resources\assemblies\test.cs' + IL_0020: ldloc.1 + IL_0021: ret +", main); + } + + [TestModule ("test.exe", SymbolReaderProvider = typeof (PdbReaderProvider), SymbolWriterProvider = typeof (PdbWriterProvider))] + public void Document (ModuleDefinition module) + { + var type = module.GetType ("Program"); + var method = type.GetMethod ("Main"); + + var sequence_point = method.Body.Instructions.Where (i => i.SequencePoint != null).First ().SequencePoint; + var document = sequence_point.Document; + + Assert.IsNotNull (document); + + Assert.AreEqual (@"c:\sources\cecil\symbols\Mono.Cecil.Pdb\Test\Resources\assemblies\test.cs", document.Url); + Assert.AreEqual (DocumentType.Text, document.Type); + Assert.AreEqual (DocumentHashAlgorithm.None, document.HashAlgorithm); + Assert.AreEqual (DocumentLanguage.CSharp, document.Language); + Assert.AreEqual (DocumentLanguageVendor.Microsoft, document.LanguageVendor); + } + + [Test] + public void CreateMethodFromScratch () + { + var module = ModuleDefinition.CreateModule ("Pan", ModuleKind.Dll); + var type = new TypeDefinition ("Pin", "Pon", TypeAttributes.Public | TypeAttributes.Abstract | TypeAttributes.Sealed, module.Import (typeof (object))); + module.Types.Add (type); + + var method = new MethodDefinition ("Pang", MethodAttributes.Public | MethodAttributes.Static, module.Import (typeof (string))); + type.Methods.Add (method); + + var body = method.Body; + + body.InitLocals = true; + + var il = body.GetILProcessor (); + var temp = new VariableDefinition ("temp", module.Import (typeof (string))); + body.Variables.Add (temp); + + il.Emit (OpCodes.Nop); + il.Emit (OpCodes.Ldstr, "hello"); + il.Emit (OpCodes.Stloc, temp); + il.Emit (OpCodes.Ldloc, temp); + il.Emit (OpCodes.Ret); + + body.Instructions [0].SequencePoint = new SequencePoint (new Document (@"C:\test.cs")) { + StartLine = 0, + StartColumn = 0, + EndLine = 0, + EndColumn = 4, + }; + + var file = Path.Combine (Path.GetTempPath (), "Pan.dll"); + module.Write (file, new WriterParameters { + SymbolWriterProvider = new PdbWriterProvider (), + }); + + module = ModuleDefinition.ReadModule (file, new ReaderParameters { + SymbolReaderProvider = new PdbReaderProvider (), + }); + + method = module.GetType ("Pin.Pon").GetMethod ("Pang"); + + Assert.AreEqual ("temp", method.Body.Variables [0].Name); + } + + static void AssertCode (string expected, MethodDefinition method) + { + Assert.IsTrue (method.HasBody); + Assert.IsNotNull (method.Body); + + System.Console.WriteLine (Formatter.FormatMethodBody (method)); + + Assert.AreEqual (Normalize (expected), Normalize (Formatter.FormatMethodBody (method))); + } + + static string Normalize (string str) + { + return str.Trim ().Replace ("\r\n", "\n"); + } + } +} diff --git a/symbols/pdb/Test/Resources/assemblies/test.exe b/symbols/pdb/Test/Resources/assemblies/test.exe new file mode 100644 index 0000000000000000000000000000000000000000..1f45491b739e7580fe39e0a14636247bab29bcb9 GIT binary patch literal 4096 zcmeHJ-EUMy6hC*nElZ(I2~r>`3|lm{*xRMlK*%m^zraFEn{Fw@tkAo6r`xOdW4Uv; z?ixcHBZ|=&eDKBaz=O|36BCIa(SLx%e?UV*LZUwKq6sk({LS3E-E9PcM;?F68#vDoXui^Xd~>4Jw(qm z`yZyWRp=@*0sG~qF?ztO0qmlj6Md@I2sbQ6jA%jkg>S-A*s@TX)&!QKEYRydw><<( zth9h8b9JIMQI=?=$y90<^-Gf2V$@2P7||V!)nKE^*&d5Fr(%@E2#noC-R*liVr`%H zB3~P|Z9U!I7W>G$8{e4d|D}7w9$MG;JjHsk0PWPbBi7prrEes6Y(!JDhqWvZ>M8xD z)c(Q!5=JZ8;0(!o&J%qIc?Wh+F7Pe4BxJ-pm`fg+o|8HH5IT0BdXAo)7=yeFJ1^}K z+bcjyf=fHPB}VI|@u#+ry2ILK;pkJ}hLixObWEwxNhyJcvW@o8Zq)cH9it6&4n1vj zg;v0SQ2Zu(C56#peOurYnqji{V;WQ$&qvmNppVf-WxcyCLt7#Qqlne8W1A>L z+i4g0PI>`+3+<)fFlN2dbs*^@9kc8Mf11+35MRO2HS{wqSznzrM6ObL$}3iEeux4t z0-aYm&4k}JIl}aO+bU45CIarzbm28_1~g?@E@CVL>ptZh zZ(iv^-o zctBO%C#24l`VW?EiVHi>j(Yxhm8-2+$AWXcXv^;uFUoVovPyfx{tGJ*Q}-pqE4mGE z4}`C26Y%innt6bK={|lrc%>;rsD|hL5{xTZqO?5l5#1Oe`ZerUo^)&oavpE=S@3b1 zg*HLcbOQDS_z~!mzKh?!TfbkGBVvam8Ha32tGr{%H%|un$YbGc;mGOIB6+GG_a)>U zdJT95`V9&Y=fMi;^Y~>X)qp8Llm&n3KAEa2CPnqXAu2#8dJ#9Twi-W%*#*9PnWwyF z9){Qy?vY09JYs!BH?X8|$2S_$5MBXIRTHRK7uapAmq89}LVh_Lu4%}s@(}eZJd?0W zDtZ)^mZ_!?m1qgkL=sC{<(`iGvTB*TzJk(v@Ek*`jv0*gs7Mvm8(?48R@10M)+EoN ztbG`G1tJ}+o()v&q2n-=Zh!NA`f$~;*)sP9?%PaqubxUW?wVc^4^1X{a_&g~fg}@w z;T8?sb9p9N<05(ZP)B<@x+!Z630#p$R($uMFqgPvh6%kCh zi{2yR8BD5im|JkOf)}n9+3@)MTm?9J5wG^56+DEAmB~rns!jyu)0i~BiN?ttqn_ZB{y#C zTb!ak$sSZ3C@6wH$V5yJ#YO1<-Zs%_0fmcGE+7F|z z4r*vP+uGD}sr|*l53-MsY@dDdcjsI3h%Qv02bNp^xgVCV|17iTf2GyujrG@~>tm00 z&uqNrKO2|n!|!Eop-#f=+1L4OHUq5(cZm#c_H#WR{@~xA9Sheo+PVqp8ZKy-<6uVtJ|D6XG=NIR> zx4%X)sfQD$@k~CYn~9X3N@o)0RCdhBn2DH?GeS{Tg@(t+5=V8jkT{|{ZIh;{XU8&W zd{zJ_lrk%b%2Je)9(o$0_(39HNfdXYLEsQA1khUd)T&&u0*|)uBU%x1j!!O}FMW1J zyWMjh+apD&qT+nZNbLnu_Jyu9$Bx;2CyF}CF02g?aCU`cpI=#H2XI%JX{f4YQL$pl zbPn&WQsd`$Ujd!Acxk& zeG^c_pY@H^|8Xh-_$;EHu(6hXRIK5AI)^0q-_oI#N|p|(rHZ47_yN!cP!HC|I$Z3VrVrTEi8qS3hMwh{1eUK>wYMd|f*hB%x*p)#b{8Fqzn%KI;d7Brc_h`VvW