using System; using System.Collections; using System.Reflection; namespace NPhilosopher.NILC { public variant NAssembly { | Assembly { AssemblyName : string; Types : list [NAssembly]; } | Type { TypeName : string; Members : list [NAssembly]; } | Method { MethodName : string; Arguments : list [NAssembly]; ReturnType : System.Type; IL : NIL; } | Argument { ArgName : string; ArgType : System.Type; } | Other } public variant NIL { | Block { Pos : int; } | Inst { Pos : int; Prefix : NIL; Opcode : uint; Mnem : string; Argument : NIL; } | TokenArg | IntArg { Size : int; } | UIntArg { USize : int; } | Int { Value : int; } | UInt { UValue : uint; } | Object { OValue : object; } } public module Reflector { public Prefixes : list [uint * string * NIL] = [ (0xFE16U, "constrained.", NIL.TokenArg()), (0xFE19U, "no.", NIL.UIntArg(8)), (0xFE1EU, "readonly.", null), (0xFE14U, "tail.", null), (0xFE12U, "unaligned.", NIL.UIntArg(8)), (0xFE13U, "volatile.", null) ]; public Opcodes : list [uint * string * NIL] = [ (0x0000U, "nop", null), (0x0001U, "break", null), (0x0025U, "dup", null), (0x0027U, "jmp", NIL.TokenArg()), (0x0028U, "call", NIL.TokenArg()), (0x0029U, "calli", NIL.TokenArg()), (0x002AU, "ret", null), (0x002BU, "br.s", NIL.Int(8)), (0x002CU, "brfalse.s", NIL.Int(8)), (0x002DU, "brtrue.s", NIL.Int(8)), (0x002EU, "beq.s", NIL.Int(8)), (0x002FU, "bge.s", NIL.Int(8)), (0x0030U, "bgt.s", NIL.Int(8)), (0x0031U, "ble.s", NIL.Int(8)), (0x0032U, "blt.s", NIL.Int(8)), (0x0033U, "bne.s", NIL.Int(8)), (0x0034U, "bge.un.s", NIL.Int(8)), (0x0035U, "bgt.un.s", NIL.Int(8)), (0x0036U, "ble.un.s", NIL.Int(8)), (0x0037U, "ble.un.s", NIL.Int(8)), (0x0038U, "br", NIL.Int(32)), (0x0039U, "brfalse", NIL.Int(32)), (0x003AU, "brtrue", NIL.Int(32)), (0x003BU, "beq", NIL.Int(32)), (0x003CU, "bge", NIL.Int(32)), (0x003DU, "bgt", NIL.Int(32)), (0x003EU, "ble", NIL.Int(32)), (0x003FU, "blt", NIL.Int(32)), (0x0040U, "bne", NIL.Int(32)), (0x0041U, "bge.un", NIL.Int(32)), (0x0042U, "bgt.un", NIL.Int(32)), (0x0043U, "ble.un", NIL.Int(32)), (0x0044U, "blt.un", NIL.Int(32)), (0x0058U, "add", null), (0x005BU, "div", null), (0x005CU, "div.un", null), (0x005FU, "and", null), (0x0067U, "conv.i1", null), (0x0068U, "conv.i2", null), (0x0069U, "conv.i4", null), (0x006AU, "conv.i8", null), (0x006BU, "conv.r4", null), (0x006CU, "conv.r8", null), (0x006DU, "conv.u4", null), (0x006EU, "conv.u8", null), (0x0072U, "ldstr", NIL.TokenArg()), (0x0076U, "conv.r.un", null), (0x0082U, "conv.ovf.i1.un", null), (0x0083U, "conv.ovf.i2.un", null), (0x0084U, "conv.ovf.i4.un", null), (0x0085U, "conv.ovf.i8.un", null), (0x0086U, "conv.ovf.u1.un", null), (0x0087U, "conv.ovf.u2.un", null), (0x0088U, "conv.ovf.u4.un", null), (0x0089U, "conv.ovf.u8.un", null), (0x008AU, "conv.ovf.i.un", null), (0x008BU, "conv.ovf.u.un", null), (0x00B3U, "conv.ovf.i1", null), (0x00B4U, "conv.ovf.u1", null), (0x00B5U, "conv.ovf.i2", null), (0x00B6U, "conv.ovf.u2", null), (0x00B7U, "conv.ovf.i4", null), (0x00B8U, "conv.ovf.u4", null), (0x00B9U, "conv.ovf.i8", null), (0x00BAU, "conv.ovf.u8", null), (0x00C3U, "ckfinite", null), (0x00D1U, "conv.u2", null), (0x00D2U, "conv.u1", null), (0x00D3U, "conv.i", null), (0x00D4U, "conv.ovf.i", null), (0x00D5U, "conv.ovf.u", null), (0x00D6U, "add.ovf", null), (0x00D7U, "add.ovf.un", null), (0x00DCU, "endfinally", null), (0x00E0U, "conv.u", null), (0xFE00U, "arglist", null), (0xFE01U, "ceq", null), (0xFE02U, "cgt", null), (0xFE03U, "cgt.un", null), (0xFE04U, "clt", null), (0xFE05U, "clt.un", null), (0xFE11U, "endfilter", null), (0xFE18U, "initblk", null), // Once you go block, you never go back ]; public Reflect(file : string) : NAssembly { mutable types : list [NAssembly] = []; def assembly = Assembly.ReflectionOnlyLoadFrom(file); foreach(t in assembly.GetTypes()) types = NAssembly.Type(t.FullName, ReflectMembers(t)) :: types; NAssembly.Assembly(assembly.FullName, types); } public ReflectMembers(t : Type) : list[NAssembly] { mutable members : list [NAssembly] = []; def flags = ( BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic ); foreach(member in t.GetMembers(flags)) { def mem = match(member.MemberType) { | MemberTypes.Method => def method = member :> MethodInfo; System.Console.WriteLine("{0}", member.Name); NAssembly.Method( MethodName=member.Name, Arguments=ReflectMethodArguments(method), ReturnType=method.ReturnType, IL={ def body = method.GetMethodBody(); if(body == null) null; else ReflectMethodIL(body, t.Module); } ); | _ => NAssembly.Other(); }; members = mem :: members; } members; } public ReflectMethodArguments(m : MethodInfo) : list [NAssembly] { mutable args : list [NAssembly] = []; foreach(param in m.GetParameters()) args = NAssembly.Argument(param.Name, param.ParameterType) :: args; args; } public ReflectMethodIL(body : MethodBody, mod : Module) : NIL.Block { def blocks = Hashtable(); def il = body.GetILAsByteArray(); mutable next : int; mutable start : int; def U32() { (il[next] :> uint | (il[next + 1] :> uint << 8) | (il[next + 2] :> uint << 16) | (il[next + 3] :> uint << 24)); } def ParseArgument(arg) : NIL { | NIL.TokenArg => def token = U32() :> int; next += 4; match(token >> 24) { | 0x0A => NIL.Object(mod.ResolveMember(token)); | 0x70 => NIL.Object(mod.ResolveString(token)); | x => System.Console.WriteLine("Table: {0:X}", x); NIL.Object(null); } | NIL.IntArg(size) => def temp = match(ParseArgument(NIL.UIntArg(size))) { | NIL.UInt(val) => val :> int; | _ => 0; }; def signmask = 1U << (size - 1); NIL.Int({ if((temp :> uint & signmask) != 0) match(size) { | 8 => -(~temp & 0xFF) - 1; | 16 => -(~temp & 0xFFFF) - 1; | 24 => -(~temp) - 1; | _ => temp; } else temp; }); | NIL.UIntArg(size) => def temp = NIL.UInt( match(size) { | 8 => il[next] :> uint; | 16 => (il[next] :> uint | (il[next + 1] :> uint << 8)); | 32 => U32(); | _ => 0U; } ); next += size >> 3; temp; | _ => null; } def ParseOpcd(opcd, prefix, opcodes) { match(opcodes) { | [] => null; | (instopcd, mnem, arg) :: rest => if(opcd == instopcd) { next++; unless(opcd & 0xFF00U == 0) next++; NIL.Inst( Pos=start, Prefix=prefix, Opcode=opcd, Mnem=mnem, Argument=ParseArgument(arg) ); } else ParseOpcd(opcd, prefix, rest); } } def Parse() { def prefix = ParseOpcd( match(il[next] :> uint) { | 0xFEU => (0xFE00U | (il[next+1] :> uint)); | x => x; }, null, Prefixes ); def opcd = match(il[next] :> uint) { | 0xFEU => (0xFE00U | (il[next+1] :> uint)); | x => x; }; def inst = ParseOpcd( opcd, prefix, Opcodes ); match(inst) { | null => System.Console.WriteLine("{0}: {1:X}", next, opcd); throw Exception(); | NIL.Inst(_, _, opcd, mnem, arg) => when(opcd == 0x002AU) // ret next = -1; System.Console.WriteLine( "{0} {1}", mnem, match(arg) { | Object(obj) => obj; | x => x; } ); } inst; } def Process(pos) { if(blocks.ContainsKey(pos)) blocks[pos] :> NIL.Block; else { mutable inst : NIL.Inst; next = pos; start = pos; while(next != -1) { inst = Parse(); } def block = NIL.Block(pos); blocks[pos] = block; block; } } Process(0); } } }