diff --git a/source/MetadataProcessor.Console/Program.cs b/source/MetadataProcessor.Console/Program.cs index 3fb34526..97eacd02 100644 --- a/source/MetadataProcessor.Console/Program.cs +++ b/source/MetadataProcessor.Console/Program.cs @@ -34,6 +34,8 @@ private sealed class MetadataProcessor internal bool VerboseMinimize { get; set; } + public bool DumpMetadata { get; internal set; } = false; + public void Parse(string fileName) { try @@ -71,6 +73,14 @@ public void Compile( { _assemblyBuilder.Write(writer); } + + if(DumpMetadata) + { + nanoDumperGenerator dumper = new nanoDumperGenerator( + _assemblyBuilder.TablesContext, + Path.ChangeExtension(fileName, "dump.txt")); + dumper.DumpAll(); + } } catch (Exception) { @@ -99,6 +109,14 @@ public void Minimize( { _assemblyBuilder.Write(writer); } + + if (DumpMetadata) + { + nanoDumperGenerator dumper = new nanoDumperGenerator( + _assemblyBuilder.TablesContext, + Path.ChangeExtension(fileName, "dump.txt")); + dumper.DumpAll(); + } } catch (Exception ex) { @@ -217,6 +235,7 @@ public static void Main(string[] args) System.Console.WriteLine("-minimize Minimizes the assembly, removing unwanted elements."); System.Console.WriteLine("-verbose Outputs each command before executing it."); System.Console.WriteLine("-verboseMinimize Turns on verbose level for the minimization phase."); + System.Console.WriteLine("-dump_all Generates a report of an assembly's metadata."); System.Console.WriteLine(""); } else if (arg == "-parse" && i + 1 < args.Length) @@ -288,6 +307,10 @@ public static void Main(string[] args) { md.GenerateDependency(args[++i]); } + else if (arg == "-dump_all" && i + 1 < args.Length) + { + md.DumpMetadata = true; + } else { System.Console.Error.WriteLine("Unknown command line option '{0}' ignored.", arg); diff --git a/source/MetadataProcessor.Core/DumpGenerator/AssemblyRef.cs b/source/MetadataProcessor.Core/DumpGenerator/AssemblyRef.cs new file mode 100644 index 00000000..c0b8841e --- /dev/null +++ b/source/MetadataProcessor.Core/DumpGenerator/AssemblyRef.cs @@ -0,0 +1,16 @@ +// +// Copyright (c) 2020 The nanoFramework project contributors +// See LICENSE file in the project root for full license information. +// + +namespace nanoFramework.Tools.MetadataProcessor.Core +{ + public class AssemblyRef + { + public string ReferenceId; + + public string Flags; + + public string Name; + } +} diff --git a/source/MetadataProcessor.Core/DumpGenerator/DumpAllTable.cs b/source/MetadataProcessor.Core/DumpGenerator/DumpAllTable.cs new file mode 100644 index 00000000..f6fdbebe --- /dev/null +++ b/source/MetadataProcessor.Core/DumpGenerator/DumpAllTable.cs @@ -0,0 +1,17 @@ +// +// Copyright (c) 2020 The nanoFramework project contributors +// See LICENSE file in the project root for full license information. +// + +using System.Collections.Generic; + +namespace nanoFramework.Tools.MetadataProcessor.Core +{ + public class DumpAllTable + { + public List AssemblyReferences = new List(); + public List TypeReferences = new List(); + public List TypeDefinitions = new List(); + public List UserStrings = new List(); + } +} diff --git a/source/MetadataProcessor.Core/DumpGenerator/DumpTemplates.cs b/source/MetadataProcessor.Core/DumpGenerator/DumpTemplates.cs new file mode 100644 index 00000000..a6f03003 --- /dev/null +++ b/source/MetadataProcessor.Core/DumpGenerator/DumpTemplates.cs @@ -0,0 +1,52 @@ +// +// Copyright (c) 2020 The nanoFramework project contributors +// See LICENSE file in the project root for full license information. +// + +namespace nanoFramework.Tools.MetadataProcessor +{ + internal partial class DumpTemplates + { + internal static string DumpAllTemplate = +@" +{{#AssemblyReferences}} +AssemblyRefProps [{{ReferenceId}}]: Flags: {{Flags}} '{{Name}}' +{{/AssemblyReferences}} +{{#TypeReferences}} +TypeRefProps [{{ReferenceId}}]: Scope: {{Scope}} '{{Name}}' +{{#MemberReferences}} + MemberRefProps [{{ReferenceId}}]: '{{Name}}' [{{Signature}}] +{{/MemberReferences}} +{{/TypeReferences}} +{{#TypeDefinitions}} +TypeDefProps [{{ReferenceId}}]: Flags: {{Flags}} Extends: {{ExtendsType}} Enclosed: {{EnclosedType}} '{{Name}}' +{{#FieldDefinitions}} + FieldDefProps [{{ReferenceId}}]: Attr: {{Attributes}} Flags: {{Flags}} '{{Name}}' [{{Signature}}] +{{/FieldDefinitions}} +{{#MethodDefinitions}} + MethodDefProps [{{ReferenceId}}]: Flags: {{Flags}} Impl: {{Implementation}} RVA: {{RVA}} '{{Name}}' [{{Signature}}] + {{#Locals}} + Locals {{Locals}} + {{/Locals}} + {{#ExceptionHandlers}} + EH: {{ExceptionHandler}} + {{/ExceptionHandlers}} + {{#ILCodeInstructionsCount}} + IL count: {{ILCodeInstructionsCount}} + {{/ILCodeInstructionsCount}} + {{#ILCode}} + {{IL}} + {{/ILCode}} +{{/MethodDefinitions}} +{{#InterfaceDefinitions}} + InterfaceImplProps [{{ReferenceId}}]: Itf: {{Interface}} +{{/InterfaceDefinitions}} + +{{/TypeDefinitions}} +{{#UserStrings}} +UserString [{{ReferenceId}}]: '{{Content}}' +{{/UserStrings}} +"; + + } +} diff --git a/source/MetadataProcessor.Core/DumpGenerator/ExceptionHandler.cs b/source/MetadataProcessor.Core/DumpGenerator/ExceptionHandler.cs new file mode 100644 index 00000000..5be67006 --- /dev/null +++ b/source/MetadataProcessor.Core/DumpGenerator/ExceptionHandler.cs @@ -0,0 +1,12 @@ +// +// Copyright (c) 2020 The nanoFramework project contributors +// See LICENSE file in the project root for full license information. +// + +namespace nanoFramework.Tools.MetadataProcessor.Core +{ + public class ExceptionHandler + { + public string Handler = ""; + } +} diff --git a/source/MetadataProcessor.Core/DumpGenerator/FieldDef.cs b/source/MetadataProcessor.Core/DumpGenerator/FieldDef.cs new file mode 100644 index 00000000..0126a40b --- /dev/null +++ b/source/MetadataProcessor.Core/DumpGenerator/FieldDef.cs @@ -0,0 +1,20 @@ +// +// Copyright (c) 2020 The nanoFramework project contributors +// See LICENSE file in the project root for full license information. +// + +namespace nanoFramework.Tools.MetadataProcessor.Core +{ + public class FieldDef + { + public string ReferenceId; + + public string Attributes; + + public string Flags; + + public string Signature; + + public string Name; + } +} diff --git a/source/MetadataProcessor.Core/DumpGenerator/ILCode.cs b/source/MetadataProcessor.Core/DumpGenerator/ILCode.cs new file mode 100644 index 00000000..bf7c9f59 --- /dev/null +++ b/source/MetadataProcessor.Core/DumpGenerator/ILCode.cs @@ -0,0 +1,12 @@ +// +// Copyright (c) 2020 The nanoFramework project contributors +// See LICENSE file in the project root for full license information. +// + +namespace nanoFramework.Tools.MetadataProcessor.Core +{ + public class ILCode + { + public string IL = ""; + } +} diff --git a/source/MetadataProcessor.Core/DumpGenerator/InterfaceDef.cs b/source/MetadataProcessor.Core/DumpGenerator/InterfaceDef.cs new file mode 100644 index 00000000..8f44b367 --- /dev/null +++ b/source/MetadataProcessor.Core/DumpGenerator/InterfaceDef.cs @@ -0,0 +1,16 @@ +// +// Copyright (c) 2020 The nanoFramework project contributors +// See LICENSE file in the project root for full license information. +// + +using System.Collections.Generic; + +namespace nanoFramework.Tools.MetadataProcessor.Core +{ + public class InterfaceDef + { + public string ReferenceId; + + public string Interface; + } +} diff --git a/source/MetadataProcessor.Core/DumpGenerator/LocalDef.cs b/source/MetadataProcessor.Core/DumpGenerator/LocalDef.cs new file mode 100644 index 00000000..e997eda7 --- /dev/null +++ b/source/MetadataProcessor.Core/DumpGenerator/LocalDef.cs @@ -0,0 +1,12 @@ +// +// Copyright (c) 2020 The nanoFramework project contributors +// See LICENSE file in the project root for full license information. +// + +namespace nanoFramework.Tools.MetadataProcessor.Core +{ + public class LocalDef + { + public string Signature; + } +} diff --git a/source/MetadataProcessor.Core/DumpGenerator/MemberRef.cs b/source/MetadataProcessor.Core/DumpGenerator/MemberRef.cs new file mode 100644 index 00000000..37c11fb7 --- /dev/null +++ b/source/MetadataProcessor.Core/DumpGenerator/MemberRef.cs @@ -0,0 +1,16 @@ +// +// Copyright (c) 2020 The nanoFramework project contributors +// See LICENSE file in the project root for full license information. +// + +namespace nanoFramework.Tools.MetadataProcessor.Core +{ + public class MemberRef + { + public string ReferenceId; + + public string Name; + + public string Signature; + } +} diff --git a/source/MetadataProcessor.Core/DumpGenerator/MethodDef.cs b/source/MetadataProcessor.Core/DumpGenerator/MethodDef.cs new file mode 100644 index 00000000..392dc15f --- /dev/null +++ b/source/MetadataProcessor.Core/DumpGenerator/MethodDef.cs @@ -0,0 +1,32 @@ +// +// Copyright (c) 2020 The nanoFramework project contributors +// See LICENSE file in the project root for full license information. +// + +using System.Collections.Generic; + +namespace nanoFramework.Tools.MetadataProcessor.Core +{ + public class MethodDef + { + public string ReferenceId; + + public string Flags; + + public string Implementation; + + public string RVA; + + public string Name; + + public string Signature; + + public string Locals; + + public List ExceptionHandlers = new List(); + + public string ILCodeInstructionsCount; + + public List ILCode = new List(); + } +} diff --git a/source/MetadataProcessor.Core/DumpGenerator/TypeDef.cs b/source/MetadataProcessor.Core/DumpGenerator/TypeDef.cs new file mode 100644 index 00000000..85be8de5 --- /dev/null +++ b/source/MetadataProcessor.Core/DumpGenerator/TypeDef.cs @@ -0,0 +1,27 @@ +// +// Copyright (c) 2020 The nanoFramework project contributors +// See LICENSE file in the project root for full license information. +// + +using System.Collections.Generic; + +namespace nanoFramework.Tools.MetadataProcessor.Core +{ + public class TypeDef + { + public string ReferenceId; + + public string Flags; + + public string ExtendsType; + + public string EnclosedType; + + public string Name; + + public List FieldDefinitions = new List(); + public List MethodDefinitions = new List(); + public List InterfaceDefinitions = new List(); + + } +} diff --git a/source/MetadataProcessor.Core/DumpGenerator/TypeRef.cs b/source/MetadataProcessor.Core/DumpGenerator/TypeRef.cs new file mode 100644 index 00000000..8a69cdd6 --- /dev/null +++ b/source/MetadataProcessor.Core/DumpGenerator/TypeRef.cs @@ -0,0 +1,20 @@ +// +// Copyright (c) 2020 The nanoFramework project contributors +// See LICENSE file in the project root for full license information. +// + +using System.Collections.Generic; + +namespace nanoFramework.Tools.MetadataProcessor.Core +{ + public class TypeRef + { + public string ReferenceId; + + public string Scope; + + public string Name; + + public List MemberReferences = new List(); + } +} diff --git a/source/MetadataProcessor.Core/DumpGenerator/UserString.cs b/source/MetadataProcessor.Core/DumpGenerator/UserString.cs new file mode 100644 index 00000000..81b5e006 --- /dev/null +++ b/source/MetadataProcessor.Core/DumpGenerator/UserString.cs @@ -0,0 +1,14 @@ +// +// Copyright (c) 2020 The nanoFramework project contributors +// See LICENSE file in the project root for full license information. +// + +namespace nanoFramework.Tools.MetadataProcessor.Core +{ + public class UserString + { + public string ReferenceId; + + public string Content; + } +} diff --git a/source/MetadataProcessor.Core/Endianness/nanoBinaryWriter.cs b/source/MetadataProcessor.Core/Endianness/nanoBinaryWriter.cs index 05d2ee10..be7a7433 100644 --- a/source/MetadataProcessor.Core/Endianness/nanoBinaryWriter.cs +++ b/source/MetadataProcessor.Core/Endianness/nanoBinaryWriter.cs @@ -233,7 +233,7 @@ public static nanoBinaryWriter CreateBigEndianBinaryWriter( } /// - /// Write single unsigned byte into underying stream. + /// Write single unsigned byte into underlying stream. /// /// Unsigned byte value for writing. public void WriteByte(byte value) @@ -242,7 +242,7 @@ public void WriteByte(byte value) } /// - /// Write single signed byte into underying stream. + /// Write single signed byte into underlying stream. /// /// Signed byte value for writing. public void WriteSByte(sbyte value) @@ -251,7 +251,7 @@ public void WriteSByte(sbyte value) } /// - /// Write version information into underying stream. + /// Write version information into underlying stream. /// /// Version information value for writing. public void WriteVersion(Version value) @@ -263,7 +263,7 @@ public void WriteVersion(Version value) } /// - /// Write raw string value (in UTF-8 encoding) into underying stream. + /// Write raw string value (in UTF-8 encoding) into underlying stream. /// /// String value for writing. public void WriteString(string value) @@ -273,7 +273,7 @@ public void WriteString(string value) } /// - /// Write raw bytes array into underying stream. + /// Write raw bytes array into underlying stream. /// /// Raw bytes array for writing. public void WriteBytes(byte[] value) @@ -282,7 +282,7 @@ public void WriteBytes(byte[] value) } /// - /// Write single signed word into underying stream. + /// Write single signed word into underlying stream. /// /// Signed word value for writing. public void WriteInt16(short value) @@ -291,7 +291,7 @@ public void WriteInt16(short value) } /// - /// Write single signed double word into underying stream. + /// Write single signed double word into underlying stream. /// /// Signed double word value for writing. public void WriteInt32(int value) @@ -300,7 +300,7 @@ public void WriteInt32(int value) } /// - /// Write single signed quad word into underying stream. + /// Write single signed quad word into underlying stream. /// /// Signed quad word value for writing. public void WriteInt64(long value) @@ -333,31 +333,31 @@ public void WriteMetadataToken(uint value) } /// - /// Write single unsigned word into underying stream. + /// Write single unsigned word into underlying stream. /// /// Unsigned word value for writing. public abstract void WriteUInt16(ushort value); /// - /// Write single signed double word into underying stream. + /// Write single signed double word into underlying stream. /// /// Unsigned double word value for writing. public abstract void WriteUInt32(uint value); /// - /// Write single signed quad word into underying stream. + /// Write single signed quad word into underlying stream. /// /// Unsigned quad word value for writing. public abstract void WriteUInt64(ulong value); /// - /// Write single floating point value (4 bytes) into underying stream. + /// Write single floating point value (4 bytes) into underlying stream. /// /// Floating point value for writing. public abstract void WriteSingle(float value); /// - /// Write single floating point value (8 bytes) into underying stream. + /// Write single floating point value (8 bytes) into underlying stream. /// /// Floating point value for writing. public abstract void WriteDouble(double value); diff --git a/source/MetadataProcessor.Core/MetadataProcessor.Core.csproj b/source/MetadataProcessor.Core/MetadataProcessor.Core.csproj index 4a01884a..d6f919bd 100644 --- a/source/MetadataProcessor.Core/MetadataProcessor.Core.csproj +++ b/source/MetadataProcessor.Core/MetadataProcessor.Core.csproj @@ -80,6 +80,19 @@ + + + + + + + + + + + + + @@ -88,6 +101,7 @@ + @@ -130,6 +144,7 @@ + diff --git a/source/MetadataProcessor.Core/Mono.Cecil/CodeWriter.cs b/source/MetadataProcessor.Core/Mono.Cecil/CodeWriter.cs index 6f333b21..a06c24e5 100644 --- a/source/MetadataProcessor.Core/Mono.Cecil/CodeWriter.cs +++ b/source/MetadataProcessor.Core/Mono.Cecil/CodeWriter.cs @@ -115,7 +115,7 @@ public static IEnumerable> PreProcessMethod( offsetChanged = true; break; case OperandType.InlineString: - stringTable.GetOrCreateStringId((string) instruction.Operand, false); + stringTable.GetOrCreateStringId((string) instruction.Operand, true); offset -= 2; offsetChanged = true; break; @@ -407,7 +407,7 @@ private void WriteOperand ( _writer.WriteDouble((double)operand); break; case OperandType.InlineString: - var stringReferenceId = _stringTable.GetOrCreateStringId((string) operand, false); + var stringReferenceId = _stringTable.GetOrCreateStringId((string) operand, true); _writer.WriteUInt16(stringReferenceId); break; case OperandType.InlineMethod: diff --git a/source/MetadataProcessor.Core/Tables/nanoMethodDefinitionTable.cs b/source/MetadataProcessor.Core/Tables/nanoMethodDefinitionTable.cs index 24e1fab7..24a7bbca 100644 --- a/source/MetadataProcessor.Core/Tables/nanoMethodDefinitionTable.cs +++ b/source/MetadataProcessor.Core/Tables/nanoMethodDefinitionTable.cs @@ -115,7 +115,7 @@ protected override void WriteSingleItem( writer.WriteUInt16(methodSignature); } - private uint GetFlags( + public static uint GetFlags( MethodDefinition method) { const uint MD_Scope_Private = 0x00000001; // Accessible only by the parent type. diff --git a/source/MetadataProcessor.Core/Tables/nanoSignaturesTable.cs b/source/MetadataProcessor.Core/Tables/nanoSignaturesTable.cs index b41bfc78..62fafc11 100644 --- a/source/MetadataProcessor.Core/Tables/nanoSignaturesTable.cs +++ b/source/MetadataProcessor.Core/Tables/nanoSignaturesTable.cs @@ -46,7 +46,7 @@ public int GetHashCode(byte[] that) static nanoSignaturesTable() { - PrimitiveTypes.Add(typeof(void).FullName, nanoCLR_DataType.DATATYPE_VOID); + PrimitiveTypes.Add(typeof(void).FullName, nanoCLR_DataType.DATATYPE_VALUETYPE); PrimitiveTypes.Add(typeof(sbyte).FullName, nanoCLR_DataType.DATATYPE_I1); PrimitiveTypes.Add(typeof(short).FullName, nanoCLR_DataType.DATATYPE_I2); @@ -66,8 +66,17 @@ static nanoSignaturesTable() PrimitiveTypes.Add(typeof(bool).FullName, nanoCLR_DataType.DATATYPE_BOOLEAN); PrimitiveTypes.Add(typeof(object).FullName, nanoCLR_DataType.DATATYPE_OBJECT); - PrimitiveTypes.Add(typeof(IntPtr).FullName, nanoCLR_DataType.DATATYPE_I4); - PrimitiveTypes.Add(typeof(UIntPtr).FullName, nanoCLR_DataType.DATATYPE_U4); + PrimitiveTypes.Add(typeof(IntPtr).FullName, nanoCLR_DataType.DATATYPE_VALUETYPE); + //PrimitiveTypes.Add(typeof(UIntPtr).FullName, nanoCLR_DataType.DATATYPE_U4); + + PrimitiveTypes.Add("System.DateTime", nanoCLR_DataType.DATATYPE_DATETIME); + PrimitiveTypes.Add("System.TimeSpan", nanoCLR_DataType.DATATYPE_TIMESPAN); + + PrimitiveTypes.Add("System.RuntimeTypeHandle", nanoCLR_DataType.DATATYPE_REFLECTION); + PrimitiveTypes.Add("System.RuntimeFieldHandle", nanoCLR_DataType.DATATYPE_REFLECTION); + PrimitiveTypes.Add("System.RuntimeMethodHandle", nanoCLR_DataType.DATATYPE_REFLECTION); + + PrimitiveTypes.Add("System.WeakReference", nanoCLR_DataType.DATATYPE_WEAKCLASS); } /// diff --git a/source/MetadataProcessor.Core/Tables/nanoStringTable.cs b/source/MetadataProcessor.Core/Tables/nanoStringTable.cs index bef09d14..c779370d 100644 --- a/source/MetadataProcessor.Core/Tables/nanoStringTable.cs +++ b/source/MetadataProcessor.Core/Tables/nanoStringTable.cs @@ -58,6 +58,8 @@ public nanoStringTable( _stringSorter = stringSorter ?? new EmptyStringSorter(); } + + /// /// Gets existing or creates new string reference identifier related to passed string value. /// @@ -156,5 +158,10 @@ public void RemoveUnusedItems(HashSet items) _idsByStrings.Remove(itemToRemove); } } + + public Dictionary GetItems() + { + return _idsByStrings; + } } } diff --git a/source/MetadataProcessor.Core/Utility/nanoCLR_DataType.cs b/source/MetadataProcessor.Core/Utility/nanoCLR_DataType.cs index a71ce5ab..aa92c752 100644 --- a/source/MetadataProcessor.Core/Utility/nanoCLR_DataType.cs +++ b/source/MetadataProcessor.Core/Utility/nanoCLR_DataType.cs @@ -6,7 +6,7 @@ namespace nanoFramework.Tools.MetadataProcessor { - internal enum nanoCLR_DataType : byte + public enum nanoCLR_DataType : byte { // these where defined @ enum CLR_DataType @@ -35,8 +35,13 @@ internal enum nanoCLR_DataType : byte DATATYPE_LAST_NONPOINTER = DATATYPE_TIMESPAN, // All the above types don't need fix-up on assignment DATATYPE_LAST_PRIMITIVE_TO_PRESERVE = DATATYPE_R8, + // All the above types can be marshaled by assignment. +#if NANOCLR_NO_ASSEMBLY_STRINGS + DATATYPE_LAST_PRIMITIVE_TO_MARSHAL = DATATYPE_STRING, +#else DATATYPE_LAST_PRIMITIVE_TO_MARSHAL = DATATYPE_TIMESPAN, +#endif // All the above types don't need fix-up on assignment. DATATYPE_LAST_PRIMITIVE = DATATYPE_STRING, @@ -46,5 +51,67 @@ internal enum nanoCLR_DataType : byte DATATYPE_VALUETYPE, // VALUETYPE DATATYPE_SZARRAY, // Shortcut for single dimension zero lower bound array SZARRAY DATATYPE_BYREF, // BYREF + + //////////////////////////////////////// + + DATATYPE_FREEBLOCK, + DATATYPE_CACHEDBLOCK, + DATATYPE_ASSEMBLY, + DATATYPE_WEAKCLASS, + DATATYPE_REFLECTION, + DATATYPE_ARRAY_BYREF, + DATATYPE_DELEGATE_HEAD, + DATATYPE_DELEGATELIST_HEAD, + DATATYPE_OBJECT_TO_EVENT, + DATATYPE_BINARY_BLOB_HEAD, + + DATATYPE_THREAD, + DATATYPE_SUBTHREAD, + DATATYPE_STACK_FRAME, + DATATYPE_TIMER_HEAD, + DATATYPE_LOCK_HEAD, + DATATYPE_LOCK_OWNER_HEAD, + DATATYPE_LOCK_REQUEST_HEAD, + DATATYPE_WAIT_FOR_OBJECT_HEAD, + DATATYPE_FINALIZER_HEAD, + DATATYPE_MEMORY_STREAM_HEAD, // SubDataType? + DATATYPE_MEMORY_STREAM_DATA, // SubDataType? + + DATATYPE_SERIALIZER_HEAD, // SubDataType? + DATATYPE_SERIALIZER_DUPLICATE, // SubDataType? + DATATYPE_SERIALIZER_STATE, // SubDataType? + + DATATYPE_ENDPOINT_HEAD, + + //These constants are shared by Debugger.dll, and cannot be conditionally compiled away. + //This adds a couple extra bytes to the lookup table. But frankly, the lookup table should probably + //be shrunk to begin with. Most of the datatypes are used just to tag memory. + //For those datatypes, perhaps we should use a subDataType instead (probably what the comments above are about). + + DATATYPE_RADIO_LAST = DATATYPE_ENDPOINT_HEAD + 3, + + DATATYPE_IO_PORT, + DATATYPE_IO_PORT_LAST = DATATYPE_RADIO_LAST + 1, + + DATATYPE_VTU_PORT_LAST = DATATYPE_IO_PORT_LAST + 1, + +#if NANOCLR_APPDOMAINS + DATATYPE_APPDOMAIN_HEAD , + DATATYPE_TRANSPARENT_PROXY , + DATATYPE_APPDOMAIN_ASSEMBLY , +#endif + DATATYPE_APPDOMAIN_LAST = DATATYPE_VTU_PORT_LAST + 3, + + DATATYPE_FIRST_INVALID, + + // Type modifies. This is exact copy of VALUES ELEMENT_TYPE_* from CorHdr.h + // + + DATATYPE_TYPE_MODIFIER = 0x40, + DATATYPE_TYPE_SENTINEL = 0x01 | DATATYPE_TYPE_MODIFIER, // sentinel for varargs + DATATYPE_TYPE_PINNED = 0x05 | DATATYPE_TYPE_MODIFIER, + DATATYPE_TYPE_R4_HFA = 0x06 | DATATYPE_TYPE_MODIFIER, // used only internally for R4 HFA types + DATATYPE_TYPE_R8_HFA = 0x07 | DATATYPE_TYPE_MODIFIER, // used only internally for R8 HFA types + } } diff --git a/source/MetadataProcessor.Core/Utility/nanoSerializationType.cs b/source/MetadataProcessor.Core/Utility/nanoSerializationType.cs index 3dd86289..050b8018 100644 --- a/source/MetadataProcessor.Core/Utility/nanoSerializationType.cs +++ b/source/MetadataProcessor.Core/Utility/nanoSerializationType.cs @@ -12,7 +12,8 @@ namespace nanoFramework.Tools.MetadataProcessor internal enum nanoSerializationType : byte { // these where defined @ typedef enum CorElementType - + ELEMENT_TYPE_END = 0x0, + ELEMENT_TYPE_VOID = 0x1, ELEMENT_TYPE_BOOLEAN = 0x2, ELEMENT_TYPE_CHAR = 0x3, ELEMENT_TYPE_I1 = 0x4, @@ -27,6 +28,43 @@ internal enum nanoSerializationType : byte ELEMENT_TYPE_R8 = 0xd, ELEMENT_TYPE_STRING = 0xe, + // every type above PTR will be simple type + ELEMENT_TYPE_PTR = 0xf, // PTR + ELEMENT_TYPE_BYREF = 0x10, // BYREF + + // Please use ELEMENT_TYPE_VALUETYPE. ELEMENT_TYPE_VALUECLASS is deprecated. + ELEMENT_TYPE_VALUETYPE = 0x11, // VALUETYPE + ELEMENT_TYPE_CLASS = 0x12, // CLASS + ELEMENT_TYPE_VAR = 0x13, // a class type variable VAR + ELEMENT_TYPE_ARRAY = 0x14, // MDARRAY ... ... + ELEMENT_TYPE_GENERICINST = 0x15, // instantiated type + ELEMENT_TYPE_TYPEDBYREF = 0x16, // This is a simple type. + + ELEMENT_TYPE_I = 0x18, // native integer size + ELEMENT_TYPE_U = 0x19, // native unsigned integer size + ELEMENT_TYPE_FNPTR = 0x1B, // FNPTR + ELEMENT_TYPE_OBJECT = 0x1C, // Shortcut for System.Object + ELEMENT_TYPE_SZARRAY = 0x1D, // Shortcut for single dimension zero lower bound array + // SZARRAY + ELEMENT_TYPE_MVAR = 0x1E, // a method type variable MVAR + + // This is only for binding + ELEMENT_TYPE_CMOD_REQD = 0x1F, // required C modifier : E_T_CMOD_REQD + ELEMENT_TYPE_CMOD_OPT = 0x20, // optional C modifier : E_T_CMOD_OPT + + // This is for signatures generated internally (which will not be persisted in any way). + ELEMENT_TYPE_INTERNAL = 0x21, // INTERNAL + + // Note that this is the max of base type excluding modifiers + ELEMENT_TYPE_MAX = 0x22, // first invalid element type + + + ELEMENT_TYPE_MODIFIER = 0x40, + ELEMENT_TYPE_SENTINEL = 0x01 | ELEMENT_TYPE_MODIFIER, // sentinel for varargs + ELEMENT_TYPE_PINNED = 0x05 | ELEMENT_TYPE_MODIFIER, + ELEMENT_TYPE_R4_HFA = 0x06 | ELEMENT_TYPE_MODIFIER, // used only internally for R4 HFA types + ELEMENT_TYPE_R8_HFA = 0x07 | ELEMENT_TYPE_MODIFIER, // used only internally for R8 HFA types + SERIALIZATION_TYPE_FIELD = 0x53, SERIALIZATION_TYPE_PROPERTY = 0x54, } diff --git a/source/MetadataProcessor.Core/nanoAssemblyBuilder.cs b/source/MetadataProcessor.Core/nanoAssemblyBuilder.cs index 5cb3e783..4a021d41 100644 --- a/source/MetadataProcessor.Core/nanoAssemblyBuilder.cs +++ b/source/MetadataProcessor.Core/nanoAssemblyBuilder.cs @@ -160,7 +160,6 @@ public void Minimize() _tablesContext.MethodDefinitionTable.RemoveUnusedItems(set); _tablesContext.MethodReferencesTable.RemoveUnusedItems(set); _tablesContext.TypeDefinitionTable.RemoveUnusedItems(set); - _tablesContext.TypeReferencesTable.RemoveUnusedItems(set); _tablesContext.TypeDefinitionTable.ResetByteCodeOffsets(); _tablesContext.AttributesTable.RemoveUnusedItems(set); _tablesContext.ResetByteCodeTable(); @@ -207,15 +206,12 @@ public void Minimize() { // remove unused interfaces // because we don't have an interface definition table - // have to do it the hard way: search the type definition that contains the interface - foreach (var t in _tablesContext.TypeDefinitionTable.Items) + // have to do it the hard way: search the type definition that contains the interface type + var ii = _tablesContext.TypeDefinitionTable.Items.FirstOrDefault(t => t.MetadataToken == i.InterfaceType.MetadataToken); + if (ii == null) { - var ii = t.Interfaces.FirstOrDefault(iRef => iRef.MetadataToken == i.MetadataToken); - if (ii == null) - { - interfacesToRemove.Add(i); - break; - } + interfacesToRemove.Add(i); + break; } } diff --git a/source/MetadataProcessor.Core/nanoDumperGenerator.cs b/source/MetadataProcessor.Core/nanoDumperGenerator.cs new file mode 100644 index 00000000..7465b934 --- /dev/null +++ b/source/MetadataProcessor.Core/nanoDumperGenerator.cs @@ -0,0 +1,387 @@ +// +// Copyright (c) 2020 The nanoFramework project contributors +// See LICENSE file in the project root for full license information. +// + +using Mono.Cecil; +using Mono.Cecil.Cil; +using Mono.Collections.Generic; +using Stubble.Core.Builders; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace nanoFramework.Tools.MetadataProcessor.Core +{ + /// + /// Dumps details for parsed assemblies and PE files. + /// + public sealed class nanoDumperGenerator + { + private readonly nanoTablesContext _tablesContext; + private readonly string _path; + + public nanoDumperGenerator( + nanoTablesContext tablesContext, + string path) + { + _tablesContext = tablesContext; + _path = path; + } + + public void DumpAll() + { + var dumpTable = new DumpAllTable(); + + DumpAssemblyReferences(dumpTable); + //DumpModuleReferences(dumpTable); + DumpTypeReferences(dumpTable); + + DumpTypeDefinitions(dumpTable); + DumpCustomAttributes(dumpTable); + DumpUserStrings(dumpTable); + + var stubble = new StubbleBuilder().Build(); + + using (var dumpFile = File.CreateText(_path)) + { + var output = stubble.Render(DumpTemplates.DumpAllTemplate, dumpTable); + dumpFile.Write(output); + } + } + + private void DumpCustomAttributes(DumpAllTable dumpTable) + { + foreach (var a in _tablesContext.AssemblyDefinition.CustomAttributes) + { + + } + } + + private void DumpUserStrings(DumpAllTable dumpTable) + { + foreach (var s in _tablesContext.StringTable.GetItems().OrderBy(i => i.Value)) + { + // don't output the empty string + if(s.Value == 0) + { + continue; + } + + // fake the metadata token from the ID + var stringMetadataToken = new MetadataToken(TokenType.String, s.Value); + + dumpTable.UserStrings.Add( + new UserString() + { + ReferenceId = stringMetadataToken.ToInt32().ToString("x8"), + Content = s.Key + }); + } + } + + private void DumpTypeDefinitions(DumpAllTable dumpTable) + { + foreach (var t in _tablesContext.TypeDefinitionTable.Items) + { + // fill type definition + var typeDef = new TypeDef() + { + ReferenceId = t.MetadataToken.ToInt32().ToString("x8"), + Name = t.FullName + }; + + var typeFlags = (uint)nanoTypeDefinitionTable.GetFlags(t); + typeDef.Flags = typeFlags.ToString("x8"); + + if (t.BaseType != null) + { + typeDef.ExtendsType = t.BaseType.MetadataToken.ToInt32().ToString("x8"); + } + else + { + var token = new MetadataToken(TokenType.TypeRef, 0); + typeDef.ExtendsType = token.ToInt32().ToString("x8"); + } + + if(t.DeclaringType != null) + { + typeDef.EnclosedType = t.DeclaringType.MetadataToken.ToInt32().ToString("x8"); + } + else + { + var token = new MetadataToken(TokenType.TypeDef, 0); + typeDef.EnclosedType = token.ToInt32().ToString("x8"); + } + + // list type fields + foreach (var f in t.Fields) + { + uint att = (uint)f.Attributes; + + var fieldDef = new FieldDef() + { + ReferenceId = f.MetadataToken.ToInt32().ToString("x8"), + Name = f.Name, + Flags = att.ToString("x8"), + Attributes = att.ToString("x8"), + Signature = PrintSignatureForType(f.FieldType) + }; + + typeDef.FieldDefinitions.Add(fieldDef); + } + + // list type methods + foreach (var m in t.Methods) + { + var methodDef = new MethodDef() + { + ReferenceId = m.MetadataToken.ToInt32().ToString("x8"), + Name = m.Name, + RVA = m.RVA.ToString("x8"), + Implementation = "Implementation", + Signature = PrintSignatureForMethod(m) + }; + + var methodFlags = nanoMethodDefinitionTable.GetFlags(m); + methodDef.Flags = methodFlags.ToString("x8"); + + if (m.HasBody) + { + // locals + if (m.Body.HasVariables) + { + methodDef.Locals = $"{m.Body.Variables.Count.ToString()}: {PrintSignatureForLocalVar(m.Body.Variables)}"; + } + + // exceptions + foreach (var eh in m.Body.ExceptionHandlers) + { + var h = new ExceptionHandler(); + + if (eh.HandlerType == Mono.Cecil.Cil.ExceptionHandlerType.Filter) + { + h.Handler = "THIS IS AN EXCEPTION HANDLER"; + } + else + { + h.Handler = "THIS IS ANoTHER EXCEPTION HANDLER"; + } + + methodDef.ExceptionHandlers.Add(h); + } + + methodDef.ILCodeInstructionsCount = m.Body.Instructions.Count.ToString(); + + // IL code + foreach (var instruction in m.Body.Instructions) + { + ILCode ilCode = new ILCode(); + + ilCode.IL += instruction.OpCode.Name.PadRight(12); + + if (instruction.Operand != null) + { + if (instruction.OpCode.OperandType == Mono.Cecil.Cil.OperandType.InlineField || + instruction.OpCode.OperandType == Mono.Cecil.Cil.OperandType.InlineMethod || + instruction.OpCode.OperandType == Mono.Cecil.Cil.OperandType.InlineType || + instruction.OpCode.OperandType == Mono.Cecil.Cil.OperandType.InlineTok || + instruction.OpCode.OperandType == Mono.Cecil.Cil.OperandType.InlineSig) + { + ilCode.IL += $"[{((IMetadataTokenProvider)instruction.Operand).MetadataToken.ToInt32().ToString("x8")}]"; + } + else if (instruction.OpCode.OperandType == Mono.Cecil.Cil.OperandType.InlineString) + { + // strings need a different processing + // get string ID from table + var stringReferenceId = _tablesContext.StringTable.GetOrCreateStringId((string)instruction.Operand, true); + + // fake the metadata token from the ID + var stringMetadataToken = new MetadataToken(TokenType.String, stringReferenceId); + + ilCode.IL += $"[{stringMetadataToken.ToInt32().ToString("x8")}]"; + } + + } + + methodDef.ILCode.Add(ilCode); + } + } + + typeDef.MethodDefinitions.Add(methodDef); + } + + // list interface implementations + foreach (var i in t.Interfaces) + { + typeDef.InterfaceDefinitions.Add( + new InterfaceDef() + { + ReferenceId = i.MetadataToken.ToInt32().ToString("x8"), + Interface = i.InterfaceType.MetadataToken.ToInt32().ToString("x8") + }); + } + + dumpTable.TypeDefinitions.Add(typeDef); + } + } + + private void DumpTypeReferences(DumpAllTable dumpTable) + { + foreach (var t in _tablesContext.TypeReferencesTable.Items) + { + ushort refId; + + var typeRef = new TypeRef() + { + Name = t.Name, + Scope = t.Scope.MetadataScopeType.ToString("x8") + }; + + if (_tablesContext.TypeReferencesTable.TryGetTypeReferenceId(t, out refId)) + { + typeRef.ReferenceId = "0x" + refId.ToString("x8"); + typeRef.Name = t.Name; + } + + // TODO + // list member refs + + dumpTable.TypeReferences.Add(typeRef); + } + } + + private void DumpModuleReferences(DumpAllTable dumpTable) + { + throw new NotImplementedException(); + } + + private void DumpAssemblyReferences(DumpAllTable dumpTable) + { + foreach(var a in _tablesContext.AssemblyReferenceTable.Items) + { + dumpTable.AssemblyReferences.Add(new AssemblyRef() + { + Name = a.Name, + ReferenceId = "0x" + _tablesContext.AssemblyReferenceTable.GetReferenceId(a).ToString("x8"), + Flags = "0x" + }); + } + } + + private string PrintSignatureForType(TypeReference type) + { + nanoCLR_DataType dataType; + if (nanoSignaturesTable.PrimitiveTypes.TryGetValue(type.FullName, out dataType)) + { + switch(dataType) + { + case nanoCLR_DataType.DATATYPE_VOID: + case nanoCLR_DataType.DATATYPE_BOOLEAN: + case nanoCLR_DataType.DATATYPE_CHAR: + case nanoCLR_DataType.DATATYPE_I1: + case nanoCLR_DataType.DATATYPE_U1: + case nanoCLR_DataType.DATATYPE_I2: + case nanoCLR_DataType.DATATYPE_U2: + case nanoCLR_DataType.DATATYPE_I4: + case nanoCLR_DataType.DATATYPE_U4: + case nanoCLR_DataType.DATATYPE_I8: + case nanoCLR_DataType.DATATYPE_U8: + case nanoCLR_DataType.DATATYPE_R4: + case nanoCLR_DataType.DATATYPE_R8: + case nanoCLR_DataType.DATATYPE_STRING: + case nanoCLR_DataType.DATATYPE_BYREF: + case nanoCLR_DataType.DATATYPE_OBJECT: + return dataType.ToString().Replace("DATATYPE_", ""); + } + } + + if (type.MetadataType == MetadataType.Class) + { + StringBuilder classSig = new StringBuilder("CLASS ["); + classSig.Append(type.MetadataToken.ToInt32().ToString("x8")); + classSig.Append("]"); + + return classSig.ToString(); + } + + if (type.MetadataType == MetadataType.ValueType) + { + StringBuilder valueTypeSig = new StringBuilder("VALUETYPE ["); + valueTypeSig.Append(type.MetadataToken.ToInt32().ToString("x8")); + valueTypeSig.Append("]"); + + return valueTypeSig.ToString(); + } + + if (type.IsArray) + { + StringBuilder arraySig = new StringBuilder("SZARRAY "); + arraySig.Append(PrintSignatureForType(type.GetElementType())); + + return arraySig.ToString(); + } + + return ""; + } + + private string PrintSignatureForMethod(MethodReference method) + { + var sig = new StringBuilder(PrintSignatureForType(method.ReturnType)); + + sig.Append("("); + + foreach(var p in method.Parameters) + { + sig.Append(" "); + sig.Append(PrintSignatureForType(p.ParameterType)); + sig.Append(" , "); + } + + // remove trailing", " + if (method.Parameters.Count > 0) + { + sig.Remove(sig.Length - 2, 2); + } + else + { + sig.Append(" "); + } + + sig.Append(")"); + + return sig.ToString(); + } + + + private string PrintSignatureForLocalVar(Collection variables) + { + StringBuilder sig = new StringBuilder(); + sig.Append("{"); + + foreach (var l in variables) + { + sig.Append(" "); + sig.Append(PrintSignatureForType(l.VariableType)); + sig.Append(" , "); + } + + // remove trailing", " + if (variables.Count > 0) + { + sig.Remove(sig.Length - 2, 2); + } + else + { + sig.Append(" "); + } + + sig.Append("}"); + + return sig.ToString(); + } + } +}