diff --git a/WoofWare.PawPrint.App/Program.fs b/WoofWare.PawPrint.App/Program.fs
index cf02c7e..773c47d 100644
--- a/WoofWare.PawPrint.App/Program.fs
+++ b/WoofWare.PawPrint.App/Program.fs
@@ -3,6 +3,7 @@ namespace WoofWare.PawPrint
open System
open System.Collections.Immutable
open System.IO
+open WoofWare.DotnetRuntimeLocator
module Program =
/// Returns the pointer to the resulting array on the heap.
@@ -34,14 +35,26 @@ module Program =
let reallyMain (argv : string[]) : int =
match argv |> Array.toList with
| dllPath :: args ->
+ let dotnetRuntimes =
+ // TODO: work out which runtime it expects to use. For now we just use the first one we find.
+ DotnetEnvironmentInfo.Get().Frameworks
+ |> Seq.map (fun fi -> Path.Combine (fi.Path, fi.Version.ToString ()))
+ |> Seq.toArray
+
use fileStream = new FileStream (dllPath, FileMode.Open, FileAccess.Read)
let dumped = Assembly.read fileStream
- let mainMethod = dumped.Methods.[dumped.MainMethod]
+
+ let entryPoint =
+ match dumped.MainMethod with
+ | None -> failwith $"No entry point in {dllPath}"
+ | Some d -> d
+
+ let mainMethod = dumped.Methods.[entryPoint]
if mainMethod.Signature.GenericParameterCount > 0 then
failwith "Refusing to execute generic main method"
- let state = IlMachineState.Initial
+ let state = IlMachineState.Initial dumped
let arrayAllocation, state =
match mainMethod.Signature.ParameterTypes |> Seq.toList with
@@ -56,20 +69,14 @@ module Program =
let state, mainThread =
state
|> IlMachineState.AddThread
- {
- LocalVariables = ImmutableArray.Empty
- IlOpIndex = 0
- EvaluationStack = EvalStack.Empty
+ { MethodState.Empty mainMethod None with
Arguments = ImmutableArray.Create (CliObject.OfManagedObject arrayAllocation)
- ExecutingMethod = dumped.Methods.[dumped.MainMethod]
- LocalMemoryPool = ()
- ReturnState = None
}
let mutable state = state
while true do
- state <- AbstractMachine.executeOneStep state dumped mainThread
+ state <- AbstractMachine.executeOneStep dotnetRuntimes state mainThread
0
| _ ->
diff --git a/WoofWare.PawPrint.App/WoofWare.PawPrint.App.fsproj b/WoofWare.PawPrint.App/WoofWare.PawPrint.App.fsproj
index ebce71d..a786f7b 100644
--- a/WoofWare.PawPrint.App/WoofWare.PawPrint.App.fsproj
+++ b/WoofWare.PawPrint.App/WoofWare.PawPrint.App.fsproj
@@ -13,6 +13,10 @@
+
+
+
+
diff --git a/WoofWare.PawPrint/AbstractMachine.fs b/WoofWare.PawPrint/AbstractMachine.fs
index 037b187..b0d03e1 100644
--- a/WoofWare.PawPrint/AbstractMachine.fs
+++ b/WoofWare.PawPrint/AbstractMachine.fs
@@ -1,7 +1,9 @@
namespace WoofWare.PawPrint
open System
+open System.Collections.Generic
open System.Collections.Immutable
+open System.IO
open System.Reflection.Metadata
open Microsoft.FSharp.Core
@@ -131,6 +133,19 @@ type MethodState =
EvaluationStack = state.EvaluationStack |> EvalStack.Push state.Arguments.[index]
}
+ static member Empty (method : MethodInfo) (returnState : MethodState option) =
+ {
+ EvaluationStack = EvalStack.Empty
+ LocalVariables =
+ // TODO: use method.LocalsInit
+ ImmutableArray.Empty
+ IlOpIndex = 0
+ Arguments = Array.zeroCreate method.Parameters.Length |> ImmutableArray.ToImmutableArray
+ ExecutingMethod = method
+ LocalMemoryPool = ()
+ ReturnState = returnState
+ }
+
type ThreadState =
{
// TODO: thread-local storage, synchronisation state, exception handling context
@@ -208,15 +223,25 @@ type IlMachineState =
/// Multiple managed heaps are allowed, but we hopefully only need one.
ManagedHeap : ManagedHeap
ThreadState : Map
+ InternedStrings : ImmutableDictionary
+ ActiveAssemblyName : string
+ LoadedAssemblies : Map
}
- static member Initial : IlMachineState =
+ member this.ActiveAssembly = this.LoadedAssemblies.[this.ActiveAssemblyName]
+
+ static member Initial (entryAssembly : DumpedAssembly) : IlMachineState =
+ let assyName = entryAssembly.ThisAssemblyDefinition.Name
+
{
NextThreadId = 0
EvalStacks = Map.empty
// CallStack = []
ManagedHeap = ManagedHeap.Empty
ThreadState = Map.empty
+ InternedStrings = ImmutableDictionary.Empty
+ ActiveAssemblyName = assyName
+ LoadedAssemblies = Map.ofList [ assyName, entryAssembly ]
}
static member AddThread (newThreadState : MethodState) (state : IlMachineState) : IlMachineState * ThreadId =
@@ -229,6 +254,9 @@ type IlMachineState =
// CallStack = state.CallStack
ManagedHeap = state.ManagedHeap
ThreadState = state.ThreadState |> Map.add thread (ThreadState.New newThreadState)
+ InternedStrings = state.InternedStrings
+ ActiveAssemblyName = state.ActiveAssemblyName
+ LoadedAssemblies = state.LoadedAssemblies
}
newState, thread
@@ -241,6 +269,19 @@ type IlMachineState =
ManagedHeap = heap
}
+ static member PushToStack (o : CliObject) (thread : ThreadId) (state : IlMachineState) =
+ { state with
+ EvalStacks =
+ state.EvalStacks
+ |> Map.change
+ thread
+ (fun s ->
+ match s with
+ | None -> failwith "tried to push to stack of nonexistent thread"
+ | Some stack -> EvalStack.Push o stack |> Some
+ )
+ }
+
static member SetArrayValue
(arrayAllocation : ManagedHeapAddress)
(v : CliObject)
@@ -294,7 +335,6 @@ module AbstractMachine =
let internal executeNullary
(state : IlMachineState)
(currentThread : ThreadId)
- (dumped : DumpedAssembly)
(op : NullaryIlOp)
: IlMachineState
=
@@ -377,27 +417,179 @@ module AbstractMachine =
| Endfinally -> failwith "todo"
| Rethrow -> failwith "todo"
| Throw -> failwith "todo"
+ | Localloc -> failwith "todo"
+ | Stind_I -> failwith "todo"
+ | Stind_I1 -> failwith "todo"
+ | Stind_I2 -> failwith "todo"
+ | Stind_I4 -> failwith "todo"
+ | Stind_I8 -> failwith "todo"
+ | Stind_R4 -> failwith "todo"
+ | Stind_R8 -> failwith "todo"
+ | Ldind_i -> failwith "todo"
+ | Ldind_i1 -> failwith "todo"
+ | Ldind_i2 -> failwith "todo"
+ | Ldind_i4 -> failwith "todo"
+ | Ldind_i8 -> failwith "todo"
+ | Ldind_u1 -> failwith "todo"
+ | Ldind_u2 -> failwith "todo"
+ | Ldind_u4 -> failwith "todo"
+ | Ldind_u8 -> failwith "todo"
+ | Ldind_r4 -> failwith "todo"
+ | Ldind_r8 -> failwith "todo"
+ | Rem -> failwith "todo"
+ | Rem_un -> failwith "todo"
+ | Volatile -> failwith "todo"
+ | Tail -> failwith "todo"
+ | Conv_ovf_i_un -> failwith "todo"
+ | Conv_ovf_u_un -> failwith "todo"
+ | Conv_ovf_i1_un -> failwith "todo"
+ | Conv_ovf_u1_un -> failwith "todo"
+ | Conv_ovf_i2_un -> failwith "todo"
+ | Conv_ovf_u2_un -> failwith "todo"
+ | Conv_ovf_i4_un -> failwith "todo"
+ | Conv_ovf_u4_un -> failwith "todo"
+ | Conv_ovf_i8_un -> failwith "todo"
+ | Conv_ovf_u8_un -> failwith "todo"
+ | Conv_ovf_i -> failwith "todo"
+ | Conv_ovf_u -> failwith "todo"
+ | Neg -> failwith "todo"
+ | Not -> failwith "todo"
+ | Ldind_ref -> failwith "todo"
+ | Stind_ref -> failwith "todo"
+ | Ldelem_i -> failwith "todo"
+ | Ldelem_i1 -> failwith "todo"
+ | Ldelem_u1 -> failwith "todo"
+ | Ldelem_i2 -> failwith "todo"
+ | Ldelem_u2 -> failwith "todo"
+ | Ldelem_i4 -> failwith "todo"
+ | Ldelem_u4 -> failwith "todo"
+ | Ldelem_i8 -> failwith "todo"
+ | Ldelem_u8 -> failwith "todo"
+ | Ldelem_r4 -> failwith "todo"
+ | Ldelem_r8 -> failwith "todo"
+ | Ldelem_ref -> failwith "todo"
+ | Stelem_i -> failwith "todo"
+ | Stelem_i1 -> failwith "todo"
+ | Stelem_u1 -> failwith "todo"
+ | Stelem_i2 -> failwith "todo"
+ | Stelem_u2 -> failwith "todo"
+ | Stelem_i4 -> failwith "todo"
+ | Stelem_u4 -> failwith "todo"
+ | Stelem_i8 -> failwith "todo"
+ | Stelem_u8 -> failwith "todo"
+ | Stelem_r4 -> failwith "todo"
+ | Stelem_r8 -> failwith "todo"
+ | Stelem_ref -> failwith "todo"
let private executeUnaryMetadata
+ (dotnetRuntimeDirs : string[])
(op : UnaryMetadataTokenIlOp)
(metadataToken : MetadataToken)
(state : IlMachineState)
- (dumped : DumpedAssembly)
(thread : ThreadId)
: IlMachineState
=
match op with
| Call ->
- let handle =
- match metadataToken.Kind with
- | HandleKind.MethodSpecification -> MethodSpecificationHandle.op_Explicit metadataToken
+ let state, methodToCall =
+ match metadataToken with
+ | MetadataToken.MethodSpecification h ->
+ let spec = state.ActiveAssembly.MethodSpecs.[h]
+
+ match spec.Method with
+ | MetadataToken.MethodDef token -> state, state.ActiveAssembly.Methods.[token]
+ | k -> failwith $"Unrecognised kind: %O{k}"
+ | MetadataToken.MemberReference h ->
+ let mem = state.ActiveAssembly.Members.[h]
+
+ let memberSig =
+ match mem.Signature with
+ | MemberSignature.Field _ -> failwith "Trying to CALL a field?!"
+ | MemberSignature.Method method -> method
+
+ let memberName : string = state.ActiveAssembly.Strings mem.Name
+
+ let parent =
+ match mem.Parent with
+ | MetadataToken.TypeReference typeRef -> state.ActiveAssembly.TypeRefs.[typeRef]
+ | parent -> failwith $"Unexpected: {parent}"
+
+ match parent.ResolutionScope with
+ | AssemblyReference r ->
+ let state, assy, newAssyName =
+ let assemblyRef = state.ActiveAssembly.AssemblyReferences.[r]
+ let assemblyName = state.ActiveAssembly.Strings assemblyRef.Name
+
+ match state.LoadedAssemblies.TryGetValue assemblyName with
+ | true, v -> state, v, assemblyName
+ | false, _ ->
+ let assy =
+ dotnetRuntimeDirs
+ |> Seq.choose (fun dir ->
+ let file = Path.Combine (dir, assemblyName + ".dll")
+
+ try
+ use f = File.OpenRead file
+ Console.Error.WriteLine $"Loading {file}"
+ Assembly.read f |> Some
+ with :? FileNotFoundException ->
+ None
+ )
+ |> Seq.exactlyOne
+
+ { state with
+ LoadedAssemblies = state.LoadedAssemblies |> Map.add assemblyName assy
+ },
+ assy,
+ assemblyName
+
+ let nsPath =
+ state.ActiveAssembly.Strings(parent.Namespace).Split '.' |> Array.toList
+
+ let targetNs = assy.NonRootNamespaces.[nsPath]
+
+ let targetType =
+ targetNs.TypeDefinitions
+ |> Seq.choose (fun td ->
+ let ty = assy.TypeDefs.[td]
+
+ if ty.Name = state.ActiveAssembly.Strings parent.Name then
+ Some ty
+ else
+ None
+ )
+ |> Seq.exactlyOne
+
+ let availableMethods =
+ targetType.Methods
+ |> List.filter (fun mi -> mi.Name = memberName)
+ |> List.filter (fun mi -> mi.Signature = memberSig)
+
+ let method =
+ match availableMethods with
+ | [] -> failwith $"Could not find member {memberName} with the right signature in CALL"
+ | [ x ] -> x
+ | _ -> failwith $"Multiple overloads matching signature for call to {memberName}!"
+
+ { state with
+ ActiveAssemblyName = newAssyName
+ },
+ method
+ | k -> failwith $"Unexpected: {k}"
+ | MetadataToken.MethodDef defn -> state, state.ActiveAssembly.Methods.[defn]
| k -> failwith $"Unrecognised kind: %O{k}"
- let method =
- dumped.Methods.[MethodDefinitionHandle.op_Explicit dumped.MethodSpecs.[handle].Method]
+ let threadState =
+ let threadState = state.ThreadState.[thread]
+
+ { threadState with
+ MethodState = MethodState.Empty methodToCall (Some threadState.MethodState)
+ }
+
+ { state with
+ ThreadState = state.ThreadState |> Map.add thread threadState
+ }
- failwith "TODO: now do this!"
- state
| Callvirt -> failwith "todo"
| Castclass -> failwith "todo"
| Newobj -> failwith "todo"
@@ -413,14 +605,61 @@ module AbstractMachine =
| Unbox_Any -> failwith "todo"
| Stelem -> failwith "todo"
| Ldelem -> failwith "todo"
+ | Initobj -> failwith "todo"
+ | Ldsflda -> failwith "todo"
+ | Ldftn -> failwith "todo"
+ | Stobj -> failwith "todo"
+ | Constrained -> failwith "todo"
+ | Ldtoken -> failwith "todo"
+ | Cpobj -> failwith "todo"
+ | Ldobj -> failwith "todo"
- let executeOneStep (state : IlMachineState) (dumped : DumpedAssembly) (thread : ThreadId) : IlMachineState =
+ let private executeUnaryStringToken
+ (op : UnaryStringTokenIlOp)
+ (sh : StringToken)
+ (state : IlMachineState)
+ (thread : ThreadId)
+ : IlMachineState
+ =
+ match op with
+ | UnaryStringTokenIlOp.Ldstr ->
+ let addressToLoad, state =
+ match state.InternedStrings.TryGetValue sh with
+ | false, _ ->
+ let toAllocate = state.ActiveAssembly.Strings sh
+ let addr, state = IlMachineState.Allocate (ReferenceType.String toAllocate) state
+
+ addr,
+ { state with
+ InternedStrings = state.InternedStrings.Add (sh, addr)
+ }
+ | true, v -> v, state
+
+ let state =
+ IlMachineState.PushToStack
+ (CliObject.Basic (BasicCliObject.ObjectReference (Some addressToLoad)))
+ thread
+ state
+ // +1 for the opcode, +4 for the bytes of the handle.
+ // TODO: some opcodes are multiple bytes! Should deal with that.
+ let mutable state = state
+
+ for i = 0 to 4 do
+ state <- IlMachineState.AdvanceProgramCounter thread state
+
+ state
+
+ let executeOneStep (dotnetRuntimePath : string[]) (state : IlMachineState) (thread : ThreadId) : IlMachineState =
let instruction = state.ThreadState.[thread].MethodState
+ Console.Error.WriteLine
+ $"[DBG] Executing one step! Now executing: {instruction.IlOpIndex} in {instruction.ExecutingMethod.Name}"
+
match instruction.ExecutingMethod.Locations.[instruction.IlOpIndex] with
- | IlOp.Nullary op -> executeNullary state thread dumped op
+ | IlOp.Nullary op -> executeNullary state thread op
| UnaryConst unaryConstIlOp -> failwith "todo"
| UnaryMetadataToken (unaryMetadataTokenIlOp, bytes) ->
- executeUnaryMetadata unaryMetadataTokenIlOp bytes state dumped thread
+ executeUnaryMetadata dotnetRuntimePath unaryMetadataTokenIlOp bytes state thread
| Switch immutableArray -> failwith "todo"
- | UnaryStringToken (unaryStringTokenIlOp, stringHandle) -> failwith "todo"
+ | UnaryStringToken (unaryStringTokenIlOp, stringHandle) ->
+ executeUnaryStringToken unaryStringTokenIlOp stringHandle state thread
diff --git a/WoofWare.PawPrint/Assembly.fs b/WoofWare.PawPrint/Assembly.fs
index 73dc9b5..7999274 100644
--- a/WoofWare.PawPrint/Assembly.fs
+++ b/WoofWare.PawPrint/Assembly.fs
@@ -9,36 +9,121 @@ open System.Reflection.Metadata.Ecma335
open System.Reflection.PortableExecutable
open Microsoft.FSharp.Core
+type AssemblyDefinition =
+ {
+ Name : string
+ }
+
+type Namespace =
+ {
+ Name : StringToken
+ Parent : NamespaceDefinitionHandle
+ TypeDefinitions : ImmutableArray
+ ExportedTypes : ImmutableArray
+ }
+
+[]
+module Namespace =
+ /// Returns also the children.
+ let make
+ (getString : StringHandle -> string)
+ (getNamespace : NamespaceDefinitionHandle -> NamespaceDefinition)
+ (ns : NamespaceDefinition)
+ : Namespace * ImmutableDictionary
+ =
+ let children = ImmutableDictionary.CreateBuilder ()
+
+ let rec inner (path : string list) (ns : NamespaceDefinition) : Namespace =
+ for child in ns.NamespaceDefinitions do
+ let rendered = getNamespace child
+ let location = getString rendered.Name :: path
+ children.Add (List.rev location, inner location rendered)
+
+ {
+ Name = StringToken.String ns.Name
+ Parent = ns.Parent
+ TypeDefinitions = ns.TypeDefinitions
+ ExportedTypes = ns.ExportedTypes
+ }
+
+ let result = inner [] ns
+ result, children.ToImmutable ()
+
+[]
+module AssemblyDefinition =
+ let make
+ (strings : StringToken -> string)
+ (assy : System.Reflection.Metadata.AssemblyDefinition)
+ : AssemblyDefinition
+ =
+ {
+ Name = strings (StringToken.String assy.Name)
+ }
+
type DumpedAssembly =
{
- Types : TypeInfo list
+ TypeDefs : IReadOnlyDictionary
+ TypeRefs : IReadOnlyDictionary
Methods : IReadOnlyDictionary
- MainMethod : MethodDefinitionHandle
+ Members : IReadOnlyDictionary>
+ MainMethod : MethodDefinitionHandle option
/// Map of four-byte int token to metadata
MethodDefinitions : Map
- MethodSpecs : ImmutableDictionary
+ MethodSpecs : ImmutableDictionary
+ Strings : StringToken -> string
+ AssemblyReferences : ImmutableDictionary
+ ThisAssemblyDefinition : AssemblyDefinition
+ RootNamespace : Namespace
+ NonRootNamespaces : ImmutableDictionary
+ // TODO: work out how to render all the strings up front, then drop this
+ PeReader : PEReader
}
+ interface IDisposable with
+ member this.Dispose () = this.PeReader.Dispose ()
+
[]
module Assembly =
let read (dllBytes : Stream) : DumpedAssembly =
- use peReader = new PEReader (dllBytes)
+ let peReader = new PEReader (dllBytes)
let metadataReader = peReader.GetMetadataReader ()
let entryPoint =
peReader.PEHeaders.CorHeader.EntryPointTokenOrRelativeVirtualAddress
- |> fun x -> if x = 0 then failwith "No entry point" else x
+ |> fun x -> if x = 0 then None else Some x
- let entryPointMethod = MetadataTokens.MethodDefinitionHandle entryPoint
+ let entryPointMethod =
+ entryPoint |> Option.map MetadataTokens.MethodDefinitionHandle
- let result =
- metadataReader.TypeDefinitions
- |> Seq.map (TypeInfo.read peReader metadataReader)
- |> Seq.toList
+ let typeRefs =
+ let builder = ImmutableDictionary.CreateBuilder ()
+ for ty in metadataReader.TypeReferences do
+ let typeRef = metadataReader.GetTypeReference ty
+
+ let result =
+ {
+ Name = StringToken.String typeRef.Name
+ Namespace = StringToken.String typeRef.Namespace
+ ResolutionScope = MetadataToken.ofEntityHandle typeRef.ResolutionScope
+ }
+
+ builder.Add (ty, result)
+
+ builder.ToImmutable ()
+
+ let typeDefs =
+ let builder = ImmutableDictionary.CreateBuilder ()
+
+ for ty in metadataReader.TypeDefinitions do
+ builder.Add (ty, TypeInfo.read peReader metadataReader ty)
+
+ builder.ToImmutable ()
+
+ // TODO: this probably misses any methods out which aren't associated with a type definition?
let methods =
- result
- |> List.collect (fun ty -> ty.Methods |> List.map (fun mi -> KeyValuePair (mi.Handle, mi)))
+ typeDefs
+ |> Seq.collect (fun (KeyValue (_, ty)) -> ty.Methods |> List.map (fun mi -> KeyValuePair (mi.Handle, mi)))
|> ImmutableDictionary.CreateRange
let methodDefnMetadata =
@@ -57,20 +142,62 @@ module Assembly =
(fun i ->
let i = i + 1
let handle = MetadataTokens.MethodSpecificationHandle i
- KeyValuePair (handle, metadataReader.GetMethodSpecification handle)
+ KeyValuePair (handle, MethodSpec.make (metadataReader.GetMethodSpecification handle))
)
|> ImmutableDictionary.CreateRange
+ let memberReferences =
+ let builder = ImmutableDictionary.CreateBuilder ()
+
+ for c in metadataReader.MemberReferences do
+ builder.Add (
+ c,
+ MemberReference.make
+ MetadataToken.ofEntityHandle
+ (metadataReader.GetMemberReference c)
+ )
+
+ builder.ToImmutable ()
+
+ // TODO: render all this up front
+ let strings (token : StringToken) =
+ match token with
+ | StringToken.String s -> metadataReader.GetString s
+ | StringToken.UserString s -> metadataReader.GetUserString s
+
+ let assemblyRefs =
+ let builder = ImmutableDictionary.CreateBuilder ()
+
+ for ref in metadataReader.AssemblyReferences do
+ builder.Add (ref, AssemblyReference.make (metadataReader.GetAssemblyReference ref))
+
+ builder.ToImmutable ()
+
+ let assy =
+ metadataReader.GetAssemblyDefinition () |> AssemblyDefinition.make strings
+
+ let rootNamespace, nonRootNamespaces =
+ metadataReader.GetNamespaceDefinitionRoot ()
+ |> Namespace.make metadataReader.GetString metadataReader.GetNamespaceDefinition
+
{
- Types = result
+ TypeDefs = typeDefs
+ TypeRefs = typeRefs
MainMethod = entryPointMethod
Methods = methods
MethodDefinitions = methodDefnMetadata
MethodSpecs = methodSpecs
+ Members = memberReferences
+ Strings = strings
+ AssemblyReferences = assemblyRefs
+ ThisAssemblyDefinition = assy
+ RootNamespace = rootNamespace
+ NonRootNamespaces = nonRootNamespaces
+ PeReader = peReader
}
let print (main : MethodDefinitionHandle) (dumped : DumpedAssembly) : unit =
- for typ in dumped.Types do
+ for KeyValue (_, typ) in dumped.TypeDefs do
printfn "\nType: %s.%s" typ.Namespace typ.Name
for method in typ.Methods do
diff --git a/WoofWare.PawPrint/IlOp.fs b/WoofWare.PawPrint/IlOp.fs
index 8bb053e..ecf11e5 100644
--- a/WoofWare.PawPrint/IlOp.fs
+++ b/WoofWare.PawPrint/IlOp.fs
@@ -1,7 +1,157 @@
namespace WoofWare.PawPrint
+open System
open System.Collections.Immutable
+open System.Reflection
open System.Reflection.Metadata
+open System.Reflection.Metadata.Ecma335
+
+type StringToken =
+ | UserString of UserStringHandle
+ | String of StringHandle
+
+[]
+module StringToken =
+ let ofInt (value : int) : StringToken =
+ match LanguagePrimitives.EnumOfValue (byte (value &&& 0xFF000000 >>> 24)) with
+ | HandleKind.UserString -> StringToken.UserString (MetadataTokens.UserStringHandle value)
+ | HandleKind.String -> StringToken.String (MetadataTokens.StringHandle value)
+ | v -> failwith $"Unrecognised string handle kind: {v}"
+
+type MetadataToken =
+ | MethodDef of MethodDefinitionHandle
+ | MethodSpecification of MethodSpecificationHandle
+ | MemberReference of MemberReferenceHandle
+ | TypeReference of TypeReferenceHandle
+ | ModuleDefinition of ModuleDefinitionHandle
+ | AssemblyReference of AssemblyReferenceHandle
+ | TypeSpecification of TypeSpecificationHandle
+ | TypeDefinition of TypeDefinitionHandle
+ | FieldDefinition of FieldDefinitionHandle
+ | Parameter of ParameterHandle
+ | InterfaceImplementation of InterfaceImplementationHandle
+
+[]
+module MetadataToken =
+ let ofInt (value : int32) : MetadataToken =
+ let asRowNum = value &&& 0x00FFFFFF
+
+ match LanguagePrimitives.EnumOfValue (byte (value &&& 0xFF000000 >>> 24)) with
+ | HandleKind.ModuleDefinition -> MetadataToken.ModuleDefinition (failwith "TODO")
+ | HandleKind.TypeReference -> MetadataToken.TypeReference (MetadataTokens.TypeReferenceHandle asRowNum)
+ | HandleKind.TypeDefinition -> MetadataToken.TypeDefinition (MetadataTokens.TypeDefinitionHandle asRowNum)
+ | HandleKind.FieldDefinition -> MetadataToken.FieldDefinition (MetadataTokens.FieldDefinitionHandle asRowNum)
+ | HandleKind.MethodDefinition -> MetadataToken.MethodDef (MetadataTokens.MethodDefinitionHandle asRowNum)
+ | HandleKind.Parameter -> MetadataToken.Parameter (MetadataTokens.ParameterHandle asRowNum)
+ | HandleKind.InterfaceImplementation ->
+ MetadataToken.InterfaceImplementation (MetadataTokens.InterfaceImplementationHandle asRowNum)
+ | HandleKind.MemberReference -> MetadataToken.MemberReference (MetadataTokens.MemberReferenceHandle asRowNum)
+ | HandleKind.Constant -> failwith "todo"
+ | HandleKind.CustomAttribute -> failwith "todo"
+ | HandleKind.DeclarativeSecurityAttribute -> failwith "todo"
+ | HandleKind.StandaloneSignature -> failwith "todo"
+ | HandleKind.EventDefinition -> failwith "todo"
+ | HandleKind.PropertyDefinition -> failwith "todo"
+ | HandleKind.MethodImplementation -> failwith "todo"
+ | HandleKind.ModuleReference -> failwith "todo"
+ | HandleKind.TypeSpecification ->
+ MetadataToken.TypeSpecification (MetadataTokens.TypeSpecificationHandle asRowNum)
+ | HandleKind.AssemblyDefinition -> failwith "todo"
+ | HandleKind.AssemblyReference ->
+ MetadataToken.AssemblyReference (MetadataTokens.AssemblyReferenceHandle asRowNum)
+ | HandleKind.AssemblyFile -> failwith "todo"
+ | HandleKind.ExportedType -> failwith "todo"
+ | HandleKind.ManifestResource -> failwith "todo"
+ | HandleKind.GenericParameter -> failwith "todo"
+ | HandleKind.MethodSpecification ->
+ MetadataToken.MethodSpecification (MetadataTokens.MethodSpecificationHandle asRowNum)
+ | HandleKind.GenericParameterConstraint -> failwith "todo"
+ | HandleKind.Document -> failwith "todo"
+ | HandleKind.MethodDebugInformation -> failwith "todo"
+ | HandleKind.LocalScope -> failwith "todo"
+ | HandleKind.LocalVariable -> failwith "todo"
+ | HandleKind.LocalConstant -> failwith "todo"
+ | HandleKind.ImportScope -> failwith "todo"
+ | HandleKind.CustomDebugInformation -> failwith "todo"
+ | HandleKind.UserString -> failwith "todo"
+ | HandleKind.Blob -> failwith "todo"
+ | HandleKind.Guid -> failwith "todo"
+ | HandleKind.String -> failwith "todo"
+ | HandleKind.NamespaceDefinition -> failwith "todo"
+ | h -> failwith $"Unrecognised kind: {h}"
+
+ let ofEntityHandle (eh : EntityHandle) : MetadataToken = ofInt (eh.GetHashCode ())
+
+type MemberSignature =
+ | Field of TypeDefn
+ | Method of TypeMethodSignature
+
+type MemberReference<'parent> =
+ {
+ Name : StringToken
+ Parent : 'parent
+ Signature : MemberSignature
+ }
+
+type MemberRefSigSwitch =
+ | Default
+ | Field
+ | VarArg
+ | Generic
+
+ static member Identify (b : byte) =
+ match b &&& 0xFuy with
+ | 0uy -> MemberRefSigSwitch.Default
+ | 5uy -> MemberRefSigSwitch.VarArg
+ | 6uy -> MemberRefSigSwitch.Field
+ | 0x10uy -> MemberRefSigSwitch.Generic
+ | n -> failwith $"Bad member ref sig: %i{n}"
+
+[]
+module MemberReference =
+ let make<'parent>
+ (makeParent : EntityHandle -> 'parent)
+ (mr : System.Reflection.Metadata.MemberReference)
+ : MemberReference<'parent>
+ =
+ let name = StringToken.String mr.Name
+
+ let signature =
+ try
+ mr.DecodeMethodSignature (TypeDefn.typeProvider, ()) |> Choice1Of2
+ with :? BadImageFormatException ->
+ mr.DecodeFieldSignature (TypeDefn.typeProvider, ()) |> Choice2Of2
+
+ let signature =
+ match signature with
+ | Choice1Of2 methodSignature -> TypeMethodSignature.make methodSignature |> MemberSignature.Method
+ | Choice2Of2 typeDefn -> MemberSignature.Field typeDefn
+
+ {
+ Name = name
+ // Horrible abuse to get this as an int
+ Parent = makeParent mr.Parent
+ Signature = signature
+ }
+
+type AssemblyReference =
+ {
+ Culture : StringToken
+ Flags : AssemblyFlags
+ Name : StringToken
+ Version : Version
+ }
+
+[]
+module AssemblyReference =
+ let make (ref : System.Reflection.Metadata.AssemblyReference) : AssemblyReference =
+ {
+ Culture = StringToken.String ref.Culture
+ Flags = ref.Flags
+ Name = StringToken.String ref.Name
+ Version = ref.Version
+ }
+
type NullaryIlOp =
| Nop
@@ -47,9 +197,15 @@ type NullaryIlOp =
| Mul_ovf_un
| Div
| Div_un
+ | Rem
+ | Rem_un
+ | Neg
+ | Not
| Shr
| Shr_un
| Shl
+ | Conv_ovf_i
+ | Conv_ovf_u
| And
| Or
| Xor
@@ -70,6 +226,63 @@ type NullaryIlOp =
| Endfinally
| Rethrow
| Throw
+ | Localloc
+ | Ldind_ref
+ | Stind_ref
+ | Stind_I
+ | Stind_I1
+ | Stind_I2
+ | Stind_I4
+ | Stind_I8
+ | Stind_R4
+ | Stind_R8
+ | Ldind_i
+ | Ldind_i1
+ | Ldind_i2
+ | Ldind_i4
+ | Ldind_i8
+ | Ldind_u1
+ | Ldind_u2
+ | Ldind_u4
+ | Ldind_u8
+ | Ldind_r4
+ | Ldind_r8
+ | Volatile
+ | Tail
+ | Conv_ovf_i_un
+ | Conv_ovf_u_un
+ | Conv_ovf_i1_un
+ | Conv_ovf_u1_un
+ | Conv_ovf_i2_un
+ | Conv_ovf_u2_un
+ | Conv_ovf_i4_un
+ | Conv_ovf_u4_un
+ | Conv_ovf_i8_un
+ | Conv_ovf_u8_un
+ | Ldelem_i
+ | Ldelem_i1
+ | Ldelem_u1
+ | Ldelem_i2
+ | Ldelem_u2
+ | Ldelem_i4
+ | Ldelem_u4
+ | Ldelem_i8
+ | Ldelem_u8
+ | Ldelem_r4
+ | Ldelem_r8
+ | Ldelem_ref
+ | Stelem_i
+ | Stelem_i1
+ | Stelem_u1
+ | Stelem_i2
+ | Stelem_u2
+ | Stelem_i4
+ | Stelem_u4
+ | Stelem_i8
+ | Stelem_u8
+ | Stelem_r4
+ | Stelem_r8
+ | Stelem_ref
type UnaryConstIlOp =
| Stloc of uint16
@@ -88,6 +301,11 @@ type UnaryConstIlOp =
| Ble_s of int8
| Bgt_s of int8
| Bge_s of int8
+ | Beq of int32
+ | Blt of int32
+ | Ble of int32
+ | Bgt of int32
+ | Bge of int32
| Bne_un_s of int8
| Bge_un_s of int8
| Bgt_un_s of int8
@@ -122,16 +340,20 @@ type UnaryMetadataTokenIlOp =
| Ldfld
| Ldflda
| Ldsfld
+ | Ldsflda
| Unbox_Any
| Stelem
| Ldelem
+ | Initobj
+ | Ldftn
+ | Stobj
+ | Constrained
+ | Ldtoken
+ | Cpobj
+ | Ldobj
type UnaryStringTokenIlOp = | Ldstr
-/// A four-byte metadata token.
-type MetadataToken = EntityHandle
-type StringToken = StringHandle
-
type IlOp =
| Nullary of NullaryIlOp
| UnaryConst of UnaryConstIlOp
diff --git a/WoofWare.PawPrint/TypeDefn.fs b/WoofWare.PawPrint/TypeDefn.fs
new file mode 100644
index 0000000..0acf843
--- /dev/null
+++ b/WoofWare.PawPrint/TypeDefn.fs
@@ -0,0 +1,169 @@
+namespace WoofWare.PawPrint
+
+open System.Collections.Immutable
+open System.Reflection.Metadata
+open System.Reflection.Metadata.Ecma335
+
+type TypeMethodSignature<'Types> =
+ {
+ Header : SignatureHeader
+ ParameterTypes : 'Types list
+ GenericParameterCount : int
+ RequiredParameterCount : int
+ ReturnType : 'Types
+ }
+
+[]
+module TypeMethodSignature =
+ let make<'T> (p : MethodSignature<'T>) : TypeMethodSignature<'T> =
+ {
+ Header = p.Header
+ ReturnType = p.ReturnType
+ ParameterTypes = List.ofSeq p.ParameterTypes
+ GenericParameterCount = p.GenericParameterCount
+ RequiredParameterCount = p.RequiredParameterCount
+ }
+
+
+type PrimitiveType =
+ | Void
+ | Boolean
+ | Char
+ | SByte
+ | Byte
+ | Int16
+ | UInt16
+ | Int32
+ | UInt32
+ | Int64
+ | UInt64
+ | Single
+ | Double
+ | String
+ | TypedReference
+ | IntPtr
+ | UIntPtr
+ | Object
+
+ static member OfEnum (ptc : PrimitiveTypeCode) : PrimitiveType =
+ match ptc with
+ | PrimitiveTypeCode.Void -> PrimitiveType.Void
+ | PrimitiveTypeCode.Boolean -> PrimitiveType.Boolean
+ | PrimitiveTypeCode.Char -> PrimitiveType.Char
+ | PrimitiveTypeCode.SByte -> PrimitiveType.SByte
+ | PrimitiveTypeCode.Byte -> PrimitiveType.Byte
+ | PrimitiveTypeCode.Int16 -> PrimitiveType.Int16
+ | PrimitiveTypeCode.UInt16 -> PrimitiveType.UInt16
+ | PrimitiveTypeCode.Int32 -> PrimitiveType.Int32
+ | PrimitiveTypeCode.UInt32 -> PrimitiveType.UInt32
+ | PrimitiveTypeCode.Int64 -> PrimitiveType.Int64
+ | PrimitiveTypeCode.UInt64 -> PrimitiveType.UInt64
+ | PrimitiveTypeCode.Single -> PrimitiveType.Single
+ | PrimitiveTypeCode.Double -> PrimitiveType.Double
+ | PrimitiveTypeCode.String -> PrimitiveType.String
+ | PrimitiveTypeCode.TypedReference -> PrimitiveType.TypedReference
+ | PrimitiveTypeCode.IntPtr -> PrimitiveType.IntPtr
+ | PrimitiveTypeCode.UIntPtr -> PrimitiveType.UIntPtr
+ | PrimitiveTypeCode.Object -> PrimitiveType.Object
+ | x -> failwithf $"Unrecognised primitive type code: %O{x}"
+
+type TypeDefn =
+ | PrimitiveType of PrimitiveType
+ | Pinned of TypeDefn
+ | Pointer of TypeDefn
+ | Byref of TypeDefn
+ | OneDimensionalArrayLowerBoundZero of elements : TypeDefn
+ | Modified of original : TypeDefn * afterMod : TypeDefn * modificationRequired : bool
+ | FromReference of SignatureTypeKind
+ | FromDefinition of SignatureTypeKind
+ | GenericInstantiation of generic : TypeDefn * args : ImmutableArray
+ | FunctionPointer of TypeMethodSignature
+ | GenericTypeParameter of index : int
+ | GenericMethodParameter of index : int
+
+[]
+module TypeDefn =
+ let fromTypeCode (s : SignatureTypeCode) : TypeDefn =
+ match s with
+ | SignatureTypeCode.Invalid -> failwith "todo"
+ | SignatureTypeCode.Void -> TypeDefn.PrimitiveType PrimitiveType.Void
+ | SignatureTypeCode.Boolean -> TypeDefn.PrimitiveType PrimitiveType.Boolean
+ | SignatureTypeCode.Char -> TypeDefn.PrimitiveType PrimitiveType.Char
+ | SignatureTypeCode.SByte -> TypeDefn.PrimitiveType PrimitiveType.SByte
+ | SignatureTypeCode.Byte -> TypeDefn.PrimitiveType PrimitiveType.Byte
+ | SignatureTypeCode.Int16 -> TypeDefn.PrimitiveType PrimitiveType.Int16
+ | SignatureTypeCode.UInt16 -> TypeDefn.PrimitiveType PrimitiveType.UInt16
+ | SignatureTypeCode.Int32 -> TypeDefn.PrimitiveType PrimitiveType.Int32
+ | SignatureTypeCode.UInt32 -> TypeDefn.PrimitiveType PrimitiveType.UInt32
+ | SignatureTypeCode.Int64 -> TypeDefn.PrimitiveType PrimitiveType.Int64
+ | SignatureTypeCode.UInt64 -> TypeDefn.PrimitiveType PrimitiveType.UInt64
+ | SignatureTypeCode.Single -> TypeDefn.PrimitiveType PrimitiveType.Single
+ | SignatureTypeCode.Double -> TypeDefn.PrimitiveType PrimitiveType.Double
+ | SignatureTypeCode.String -> TypeDefn.PrimitiveType PrimitiveType.String
+ | SignatureTypeCode.Pointer -> failwith "todo"
+ | SignatureTypeCode.ByReference -> failwith "TODO"
+ | SignatureTypeCode.GenericTypeParameter -> failwith "todo"
+ | SignatureTypeCode.Array -> failwith "todo"
+ | SignatureTypeCode.GenericTypeInstance -> failwith "todo"
+ | SignatureTypeCode.TypedReference -> TypeDefn.PrimitiveType PrimitiveType.TypedReference
+ | SignatureTypeCode.IntPtr -> TypeDefn.PrimitiveType PrimitiveType.IntPtr
+ | SignatureTypeCode.UIntPtr -> failwith "todo"
+ | SignatureTypeCode.FunctionPointer -> failwith "todo"
+ | SignatureTypeCode.Object -> failwith "todo"
+ | SignatureTypeCode.SZArray -> failwith "todo"
+ | SignatureTypeCode.GenericMethodParameter -> failwith "todo"
+ | SignatureTypeCode.RequiredModifier -> failwith "todo"
+ | SignatureTypeCode.OptionalModifier -> failwith "todo"
+ | SignatureTypeCode.TypeHandle -> failwith "todo"
+ | SignatureTypeCode.Sentinel -> failwith "todo"
+ | SignatureTypeCode.Pinned -> failwith "todo"
+ | x -> failwith $"Unrecognised type code: {x}"
+
+ let typeProvider =
+ { new ISignatureTypeProvider with
+ member this.GetArrayType (elementType : TypeDefn, shape : ArrayShape) : TypeDefn = failwith "TODO"
+ member this.GetByReferenceType (elementType : TypeDefn) : TypeDefn = TypeDefn.Byref elementType
+
+ member this.GetSZArrayType (elementType : TypeDefn) : TypeDefn =
+ TypeDefn.OneDimensionalArrayLowerBoundZero elementType
+
+ member this.GetPrimitiveType (elementType : PrimitiveTypeCode) : TypeDefn =
+ PrimitiveType.OfEnum elementType |> TypeDefn.PrimitiveType
+
+ member this.GetGenericInstantiation
+ (generic : TypeDefn, typeArguments : ImmutableArray)
+ : TypeDefn
+ =
+ TypeDefn.GenericInstantiation (generic, typeArguments)
+
+ member this.GetTypeFromDefinition
+ (reader : MetadataReader, handle : TypeDefinitionHandle, rawTypeKind : byte)
+ : TypeDefn
+ =
+ let handle : EntityHandle = TypeDefinitionHandle.op_Implicit handle
+ let typeKind = reader.ResolveSignatureTypeKind (handle, rawTypeKind)
+
+ TypeDefn.FromDefinition typeKind
+
+ member this.GetTypeFromReference
+ (reader : MetadataReader, handle : TypeReferenceHandle, rawTypeKind : byte)
+ : TypeDefn
+ =
+ let handle : EntityHandle = TypeReferenceHandle.op_Implicit handle
+ let typeKind = reader.ResolveSignatureTypeKind (handle, rawTypeKind)
+ TypeDefn.FromReference typeKind
+
+ member this.GetPointerType (typeCode : TypeDefn) : TypeDefn = TypeDefn.Pointer typeCode
+
+ member this.GetFunctionPointerType (signature) =
+ TypeDefn.FunctionPointer (TypeMethodSignature.make signature)
+
+ member this.GetGenericMethodParameter (genericContext, index) = TypeDefn.GenericMethodParameter index
+ member this.GetGenericTypeParameter (genericContext, index) = TypeDefn.GenericTypeParameter index
+
+ member this.GetModifiedType (modifier, unmodifiedType, isRequired) =
+ TypeDefn.Modified (unmodifiedType, modifier, isRequired)
+
+ member this.GetPinnedType (elementType) = TypeDefn.Pinned elementType
+ member this.GetTypeFromSpecification (reader, genericContext, handle, rawTypeKind) = failwith "todo"
+ }
diff --git a/WoofWare.PawPrint/TypeInfo.fs b/WoofWare.PawPrint/TypeInfo.fs
index 707cd30..47bee8b 100644
--- a/WoofWare.PawPrint/TypeInfo.fs
+++ b/WoofWare.PawPrint/TypeInfo.fs
@@ -3,7 +3,9 @@ namespace WoofWare.PawPrint
#nowarn "9"
open System
+open System.Collections.Generic
open System.Collections.Immutable
+open System.Reflection
open System.Reflection.Metadata
open System.Reflection.Metadata.Ecma335
open System.Reflection.PortableExecutable
@@ -22,83 +24,19 @@ type GenericParameter =
SequenceNumber : int
}
-type TypeMethodSignature<'Types> =
+type MethodSpec =
{
- Header : SignatureHeader
- ParameterTypes : ImmutableArray<'Types>
- GenericParameterCount : int
- RequiredParameterCount : int
- ReturnType : 'Types
+ Method : MetadataToken
}
[]
-module TypeMethodSignature =
- let make<'T> (p : MethodSignature<'T>) : TypeMethodSignature<'T> =
+module MethodSpec =
+ let make (p : MethodSpecification) : MethodSpec =
{
- Header = p.Header
- ReturnType = p.ReturnType
- ParameterTypes = p.ParameterTypes
- GenericParameterCount = p.GenericParameterCount
- RequiredParameterCount = p.RequiredParameterCount
+ // Horrible abuse to get this as an int
+ Method = MetadataToken.ofInt (p.Method.GetHashCode ())
}
-type PrimitiveType =
- | Void
- | Boolean
- | Char
- | SByte
- | Byte
- | Int16
- | UInt16
- | Int32
- | UInt32
- | Int64
- | UInt64
- | Single
- | Double
- | String
- | TypedReference
- | IntPtr
- | UIntPtr
- | Object
-
- static member OfEnum (ptc : PrimitiveTypeCode) : PrimitiveType =
- match ptc with
- | PrimitiveTypeCode.Void -> PrimitiveType.Void
- | PrimitiveTypeCode.Boolean -> PrimitiveType.Boolean
- | PrimitiveTypeCode.Char -> PrimitiveType.Char
- | PrimitiveTypeCode.SByte -> PrimitiveType.SByte
- | PrimitiveTypeCode.Byte -> PrimitiveType.Byte
- | PrimitiveTypeCode.Int16 -> PrimitiveType.Int16
- | PrimitiveTypeCode.UInt16 -> PrimitiveType.UInt16
- | PrimitiveTypeCode.Int32 -> PrimitiveType.Int32
- | PrimitiveTypeCode.UInt32 -> PrimitiveType.UInt32
- | PrimitiveTypeCode.Int64 -> PrimitiveType.Int64
- | PrimitiveTypeCode.UInt64 -> PrimitiveType.UInt64
- | PrimitiveTypeCode.Single -> PrimitiveType.Single
- | PrimitiveTypeCode.Double -> PrimitiveType.Double
- | PrimitiveTypeCode.String -> PrimitiveType.String
- | PrimitiveTypeCode.TypedReference -> PrimitiveType.TypedReference
- | PrimitiveTypeCode.IntPtr -> PrimitiveType.IntPtr
- | PrimitiveTypeCode.UIntPtr -> PrimitiveType.UIntPtr
- | PrimitiveTypeCode.Object -> PrimitiveType.Object
- | x -> failwithf $"Unrecognised primitive type code: %O{x}"
-
-type TypeDefn =
- | PrimitiveType of PrimitiveType
- | Pinned of TypeDefn
- | Pointer of TypeDefn
- | Byref of TypeDefn
- | OneDimensionalArrayLowerBoundZero of elements : TypeDefn
- | Modified of original : TypeDefn * afterMod : TypeDefn * modificationRequired : bool
- | FromReference of SignatureTypeKind
- | FromDefinition of SignatureTypeKind
- | GenericInstantiation of generic : TypeDefn * args : ImmutableArray
- | FunctionPointer of TypeMethodSignature
- | GenericTypeParameter of index : int
- | GenericMethodParameter of index : int
-
-
type MethodInfo =
{
Handle : MethodDefinitionHandle
@@ -110,6 +48,8 @@ type MethodInfo =
Parameters : Parameter ImmutableArray
Generics : GenericParameter ImmutableArray
Signature : TypeMethodSignature
+ IsPinvokeImpl : bool
+ LocalsInit : bool
}
type TypeInfo =
@@ -117,6 +57,14 @@ type TypeInfo =
Namespace : string
Name : string
Methods : MethodInfo list
+ MethodImpls : ImmutableDictionary
+ }
+
+type TypeRef =
+ {
+ Name : StringToken
+ Namespace : StringToken
+ ResolutionScope : MetadataToken
}
[]
@@ -131,14 +79,23 @@ module TypeInfo =
LanguagePrimitives.EnumOfValue (uint16 op)
let private readMetadataToken (reader : byref) : MetadataToken =
- reader.ReadUInt32 () |> int |> MetadataTokens.EntityHandle
+ reader.ReadUInt32 () |> int |> MetadataToken.ofInt
let private readStringToken (reader : byref) : StringToken =
- reader.ReadUInt32 () |> int |> MetadataTokens.StringHandle
+ let value = reader.ReadUInt32 () |> int
+ StringToken.ofInt value
- let private readMethodBody (peReader : PEReader) (methodDef : MethodDefinition) : (IlOp * int) list =
+ type private MethodBody =
+ {
+ Instructions : (IlOp * int) list
+ LocalInit : bool
+ MaxStackSize : int
+ ExceptionRegions : ImmutableArray
+ }
+
+ let private readMethodBody (peReader : PEReader) (methodDef : MethodDefinition) : MethodBody option =
if methodDef.RelativeVirtualAddress = 0 then
- []
+ None
else
let methodBody = peReader.GetMethodBody methodDef.RelativeVirtualAddress
let ilBytes = methodBody.GetILBytes ()
@@ -213,11 +170,11 @@ module TypeInfo =
| ILOpCode.Br -> IlOp.UnaryConst (UnaryConstIlOp.Br (reader.ReadInt32 ()))
| ILOpCode.Brfalse -> IlOp.UnaryConst (UnaryConstIlOp.Brfalse (reader.ReadInt32 ()))
| ILOpCode.Brtrue -> IlOp.UnaryConst (UnaryConstIlOp.Brtrue (reader.ReadInt32 ()))
- | ILOpCode.Beq -> failwith "todo"
- | ILOpCode.Bge -> failwith "todo"
- | ILOpCode.Bgt -> failwith "todo"
- | ILOpCode.Ble -> failwith "todo"
- | ILOpCode.Blt -> failwith "todo"
+ | ILOpCode.Beq -> IlOp.UnaryConst (UnaryConstIlOp.Beq (reader.ReadInt32 ()))
+ | ILOpCode.Bge -> IlOp.UnaryConst (UnaryConstIlOp.Bge (reader.ReadInt32 ()))
+ | ILOpCode.Bgt -> IlOp.UnaryConst (UnaryConstIlOp.Bgt (reader.ReadInt32 ()))
+ | ILOpCode.Ble -> IlOp.UnaryConst (UnaryConstIlOp.Ble (reader.ReadInt32 ()))
+ | ILOpCode.Blt -> IlOp.UnaryConst (UnaryConstIlOp.Blt (reader.ReadInt32 ()))
| ILOpCode.Bne_un -> IlOp.UnaryConst (UnaryConstIlOp.Bne_un (reader.ReadInt32 ()))
| ILOpCode.Bge_un -> IlOp.UnaryConst (UnaryConstIlOp.Bge_un (reader.ReadInt32 ()))
| ILOpCode.Bgt_un -> IlOp.UnaryConst (UnaryConstIlOp.Bgt_un (reader.ReadInt32 ()))
@@ -236,39 +193,39 @@ module TypeInfo =
result.Add (reader.ReadInt32 ())
IlOp.Switch (result.ToImmutable ())
- | ILOpCode.Ldind_i1 -> failwith "todo"
- | ILOpCode.Ldind_u1 -> failwith "todo"
- | ILOpCode.Ldind_i2 -> failwith "todo"
- | ILOpCode.Ldind_u2 -> failwith "todo"
- | ILOpCode.Ldind_i4 -> failwith "todo"
- | ILOpCode.Ldind_u4 -> failwith "todo"
- | ILOpCode.Ldind_i8 -> failwith "todo"
- | ILOpCode.Ldind_i -> failwith "todo"
- | ILOpCode.Ldind_r4 -> failwith "todo"
- | ILOpCode.Ldind_r8 -> failwith "todo"
- | ILOpCode.Ldind_ref -> failwith "todo"
- | ILOpCode.Stind_ref -> failwith "todo"
- | ILOpCode.Stind_i1 -> failwith "todo"
- | ILOpCode.Stind_i2 -> failwith "todo"
- | ILOpCode.Stind_i4 -> failwith "todo"
- | ILOpCode.Stind_i8 -> failwith "todo"
- | ILOpCode.Stind_r4 -> failwith "todo"
- | ILOpCode.Stind_r8 -> failwith "todo"
+ | ILOpCode.Ldind_i -> IlOp.Nullary NullaryIlOp.Ldind_i
+ | ILOpCode.Ldind_i1 -> IlOp.Nullary NullaryIlOp.Ldind_i1
+ | ILOpCode.Ldind_u1 -> IlOp.Nullary NullaryIlOp.Ldind_u1
+ | ILOpCode.Ldind_i2 -> IlOp.Nullary NullaryIlOp.Ldind_i2
+ | ILOpCode.Ldind_u2 -> IlOp.Nullary NullaryIlOp.Ldind_u2
+ | ILOpCode.Ldind_i4 -> IlOp.Nullary NullaryIlOp.Ldind_i4
+ | ILOpCode.Ldind_u4 -> IlOp.Nullary NullaryIlOp.Ldind_u4
+ | ILOpCode.Ldind_i8 -> IlOp.Nullary NullaryIlOp.Ldind_i8
+ | ILOpCode.Ldind_r4 -> IlOp.Nullary NullaryIlOp.Ldind_r4
+ | ILOpCode.Ldind_r8 -> IlOp.Nullary NullaryIlOp.Ldind_r8
+ | ILOpCode.Ldind_ref -> IlOp.Nullary NullaryIlOp.Ldind_ref
+ | ILOpCode.Stind_ref -> IlOp.Nullary NullaryIlOp.Stind_ref
+ | ILOpCode.Stind_i1 -> IlOp.Nullary NullaryIlOp.Stind_I1
+ | ILOpCode.Stind_i2 -> IlOp.Nullary NullaryIlOp.Stind_I2
+ | ILOpCode.Stind_i4 -> IlOp.Nullary NullaryIlOp.Stind_I4
+ | ILOpCode.Stind_i8 -> IlOp.Nullary NullaryIlOp.Stind_I8
+ | ILOpCode.Stind_r4 -> IlOp.Nullary NullaryIlOp.Stind_R4
+ | ILOpCode.Stind_r8 -> IlOp.Nullary NullaryIlOp.Stind_R8
| ILOpCode.Add -> IlOp.Nullary NullaryIlOp.Add
| ILOpCode.Sub -> IlOp.Nullary NullaryIlOp.Sub
| ILOpCode.Mul -> IlOp.Nullary NullaryIlOp.Mul
| ILOpCode.Div -> IlOp.Nullary NullaryIlOp.Div
| ILOpCode.Div_un -> IlOp.Nullary NullaryIlOp.Div_un
- | ILOpCode.Rem -> failwith "todo"
- | ILOpCode.Rem_un -> failwith "todo"
+ | ILOpCode.Rem -> IlOp.Nullary NullaryIlOp.Rem
+ | ILOpCode.Rem_un -> IlOp.Nullary NullaryIlOp.Rem_un
| ILOpCode.And -> IlOp.Nullary NullaryIlOp.And
| ILOpCode.Or -> IlOp.Nullary NullaryIlOp.Or
| ILOpCode.Xor -> IlOp.Nullary NullaryIlOp.Xor
| ILOpCode.Shl -> IlOp.Nullary NullaryIlOp.Shl
| ILOpCode.Shr -> IlOp.Nullary NullaryIlOp.Shr
| ILOpCode.Shr_un -> IlOp.Nullary NullaryIlOp.Shr_un
- | ILOpCode.Neg -> failwith "todo"
- | ILOpCode.Not -> failwith "todo"
+ | ILOpCode.Neg -> IlOp.Nullary NullaryIlOp.Neg
+ | ILOpCode.Not -> IlOp.Nullary NullaryIlOp.Not
| ILOpCode.Conv_i1 -> IlOp.Nullary NullaryIlOp.Conv_I1
| ILOpCode.Conv_i2 -> IlOp.Nullary NullaryIlOp.Conv_I2
| ILOpCode.Conv_i4 -> IlOp.Nullary NullaryIlOp.Conv_I4
@@ -279,8 +236,10 @@ module TypeInfo =
| ILOpCode.Conv_u8 -> IlOp.Nullary NullaryIlOp.Conv_U8
| ILOpCode.Callvirt ->
IlOp.UnaryMetadataToken (UnaryMetadataTokenIlOp.Callvirt, readMetadataToken &reader)
- | ILOpCode.Cpobj -> failwith "todo"
- | ILOpCode.Ldobj -> failwith "todo"
+ | ILOpCode.Cpobj ->
+ IlOp.UnaryMetadataToken (UnaryMetadataTokenIlOp.Cpobj, readMetadataToken &reader)
+ | ILOpCode.Ldobj ->
+ IlOp.UnaryMetadataToken (UnaryMetadataTokenIlOp.Ldobj, readMetadataToken &reader)
| ILOpCode.Ldstr -> IlOp.UnaryStringToken (UnaryStringTokenIlOp.Ldstr, readStringToken &reader)
| ILOpCode.Newobj ->
IlOp.UnaryMetadataToken (UnaryMetadataTokenIlOp.Newobj, readMetadataToken &reader)
@@ -299,20 +258,22 @@ module TypeInfo =
IlOp.UnaryMetadataToken (UnaryMetadataTokenIlOp.Stfld, readMetadataToken &reader)
| ILOpCode.Ldsfld ->
IlOp.UnaryMetadataToken (UnaryMetadataTokenIlOp.Ldsfld, readMetadataToken &reader)
- | ILOpCode.Ldsflda -> failwith "todo"
+ | ILOpCode.Ldsflda ->
+ IlOp.UnaryMetadataToken (UnaryMetadataTokenIlOp.Ldsflda, readMetadataToken &reader)
| ILOpCode.Stsfld ->
IlOp.UnaryMetadataToken (UnaryMetadataTokenIlOp.Stsfld, readMetadataToken &reader)
- | ILOpCode.Stobj -> failwith "todo"
- | ILOpCode.Conv_ovf_i1_un -> failwith "todo"
- | ILOpCode.Conv_ovf_i2_un -> failwith "todo"
- | ILOpCode.Conv_ovf_i4_un -> failwith "todo"
- | ILOpCode.Conv_ovf_i8_un -> failwith "todo"
- | ILOpCode.Conv_ovf_u1_un -> failwith "todo"
- | ILOpCode.Conv_ovf_u2_un -> failwith "todo"
- | ILOpCode.Conv_ovf_u4_un -> failwith "todo"
- | ILOpCode.Conv_ovf_u8_un -> failwith "todo"
- | ILOpCode.Conv_ovf_i_un -> failwith "todo"
- | ILOpCode.Conv_ovf_u_un -> failwith "todo"
+ | ILOpCode.Stobj ->
+ IlOp.UnaryMetadataToken (UnaryMetadataTokenIlOp.Stobj, readMetadataToken &reader)
+ | ILOpCode.Conv_ovf_i_un -> IlOp.Nullary NullaryIlOp.Conv_ovf_i_un
+ | ILOpCode.Conv_ovf_i1_un -> IlOp.Nullary NullaryIlOp.Conv_ovf_i1_un
+ | ILOpCode.Conv_ovf_i2_un -> IlOp.Nullary NullaryIlOp.Conv_ovf_i2_un
+ | ILOpCode.Conv_ovf_i4_un -> IlOp.Nullary NullaryIlOp.Conv_ovf_i4_un
+ | ILOpCode.Conv_ovf_i8_un -> IlOp.Nullary NullaryIlOp.Conv_ovf_i8_un
+ | ILOpCode.Conv_ovf_u_un -> IlOp.Nullary NullaryIlOp.Conv_ovf_u_un
+ | ILOpCode.Conv_ovf_u1_un -> IlOp.Nullary NullaryIlOp.Conv_ovf_u1_un
+ | ILOpCode.Conv_ovf_u2_un -> IlOp.Nullary NullaryIlOp.Conv_ovf_u2_un
+ | ILOpCode.Conv_ovf_u4_un -> IlOp.Nullary NullaryIlOp.Conv_ovf_u4_un
+ | ILOpCode.Conv_ovf_u8_un -> IlOp.Nullary NullaryIlOp.Conv_ovf_u8_un
| ILOpCode.Box ->
IlOp.UnaryMetadataToken (UnaryMetadataTokenIlOp.Box, readMetadataToken &reader)
| ILOpCode.Newarr ->
@@ -320,25 +281,25 @@ module TypeInfo =
| ILOpCode.Ldlen -> IlOp.Nullary NullaryIlOp.LdLen
| ILOpCode.Ldelema ->
IlOp.UnaryMetadataToken (UnaryMetadataTokenIlOp.Ldelema, readMetadataToken &reader)
- | ILOpCode.Ldelem_i1 -> failwith "todo"
- | ILOpCode.Ldelem_u1 -> failwith "todo"
- | ILOpCode.Ldelem_i2 -> failwith "todo"
- | ILOpCode.Ldelem_u2 -> failwith "todo"
- | ILOpCode.Ldelem_i4 -> failwith "todo"
- | ILOpCode.Ldelem_u4 -> failwith "todo"
- | ILOpCode.Ldelem_i8 -> failwith "todo"
- | ILOpCode.Ldelem_i -> failwith "todo"
- | ILOpCode.Ldelem_r4 -> failwith "todo"
- | ILOpCode.Ldelem_r8 -> failwith "todo"
- | ILOpCode.Ldelem_ref -> failwith "todo"
- | ILOpCode.Stelem_i -> failwith "todo"
- | ILOpCode.Stelem_i1 -> failwith "todo"
- | ILOpCode.Stelem_i2 -> failwith "todo"
- | ILOpCode.Stelem_i4 -> failwith "todo"
- | ILOpCode.Stelem_i8 -> failwith "todo"
- | ILOpCode.Stelem_r4 -> failwith "todo"
- | ILOpCode.Stelem_r8 -> failwith "todo"
- | ILOpCode.Stelem_ref -> failwith "todo"
+ | ILOpCode.Ldelem_i1 -> IlOp.Nullary NullaryIlOp.Ldelem_i1
+ | ILOpCode.Ldelem_u1 -> IlOp.Nullary NullaryIlOp.Ldelem_u1
+ | ILOpCode.Ldelem_i2 -> IlOp.Nullary NullaryIlOp.Ldelem_i2
+ | ILOpCode.Ldelem_u2 -> IlOp.Nullary NullaryIlOp.Ldelem_u2
+ | ILOpCode.Ldelem_i4 -> IlOp.Nullary NullaryIlOp.Ldelem_i4
+ | ILOpCode.Ldelem_u4 -> IlOp.Nullary NullaryIlOp.Ldelem_u4
+ | ILOpCode.Ldelem_i8 -> IlOp.Nullary NullaryIlOp.Ldelem_i8
+ | ILOpCode.Ldelem_i -> IlOp.Nullary NullaryIlOp.Ldelem_i
+ | ILOpCode.Ldelem_r4 -> IlOp.Nullary NullaryIlOp.Ldelem_r4
+ | ILOpCode.Ldelem_r8 -> IlOp.Nullary NullaryIlOp.Ldelem_r8
+ | ILOpCode.Ldelem_ref -> IlOp.Nullary NullaryIlOp.Ldelem_ref
+ | ILOpCode.Stelem_i -> IlOp.Nullary NullaryIlOp.Stelem_i
+ | ILOpCode.Stelem_i1 -> IlOp.Nullary NullaryIlOp.Stelem_i1
+ | ILOpCode.Stelem_i2 -> IlOp.Nullary NullaryIlOp.Stelem_i2
+ | ILOpCode.Stelem_i4 -> IlOp.Nullary NullaryIlOp.Stelem_i4
+ | ILOpCode.Stelem_i8 -> IlOp.Nullary NullaryIlOp.Stelem_i8
+ | ILOpCode.Stelem_r4 -> IlOp.Nullary NullaryIlOp.Stelem_r4
+ | ILOpCode.Stelem_r8 -> IlOp.Nullary NullaryIlOp.Stelem_r8
+ | ILOpCode.Stelem_ref -> IlOp.Nullary NullaryIlOp.Stelem_ref
| ILOpCode.Ldelem ->
IlOp.UnaryMetadataToken (UnaryMetadataTokenIlOp.Ldelem, readMetadataToken &reader)
| ILOpCode.Stelem ->
@@ -356,30 +317,32 @@ module TypeInfo =
| ILOpCode.Refanyval -> failwith "todo"
| ILOpCode.Ckfinite -> failwith "todo"
| ILOpCode.Mkrefany -> failwith "todo"
- | ILOpCode.Ldtoken -> failwith "todo"
+ | ILOpCode.Ldtoken ->
+ IlOp.UnaryMetadataToken (UnaryMetadataTokenIlOp.Ldtoken, readMetadataToken &reader)
| ILOpCode.Conv_u2 -> IlOp.Nullary NullaryIlOp.Conv_U2
| ILOpCode.Conv_u1 -> IlOp.Nullary NullaryIlOp.Conv_U1
| ILOpCode.Conv_i -> IlOp.Nullary NullaryIlOp.Conv_I
- | ILOpCode.Conv_ovf_i -> failwith "todo"
- | ILOpCode.Conv_ovf_u -> failwith "todo"
- | ILOpCode.Add_ovf -> failwith "todo"
- | ILOpCode.Add_ovf_un -> failwith "todo"
- | ILOpCode.Mul_ovf -> failwith "todo"
- | ILOpCode.Mul_ovf_un -> failwith "todo"
- | ILOpCode.Sub_ovf -> failwith "todo"
- | ILOpCode.Sub_ovf_un -> failwith "todo"
+ | ILOpCode.Conv_ovf_i -> IlOp.Nullary NullaryIlOp.Conv_ovf_i
+ | ILOpCode.Conv_ovf_u -> IlOp.Nullary NullaryIlOp.Conv_ovf_u
+ | ILOpCode.Add_ovf -> IlOp.Nullary NullaryIlOp.Add_ovf
+ | ILOpCode.Add_ovf_un -> IlOp.Nullary NullaryIlOp.Add_ovf_un
+ | ILOpCode.Mul_ovf -> IlOp.Nullary NullaryIlOp.Mul_ovf
+ | ILOpCode.Mul_ovf_un -> IlOp.Nullary NullaryIlOp.Mul_ovf_un
+ | ILOpCode.Sub_ovf -> IlOp.Nullary NullaryIlOp.Sub_ovf
+ | ILOpCode.Sub_ovf_un -> IlOp.Nullary NullaryIlOp.Sub_ovf_un
| ILOpCode.Endfinally -> IlOp.Nullary NullaryIlOp.Endfinally
| ILOpCode.Leave -> IlOp.UnaryConst (UnaryConstIlOp.Leave (reader.ReadInt32 ()))
| ILOpCode.Leave_s -> IlOp.UnaryConst (UnaryConstIlOp.Leave_s (reader.ReadSByte ()))
| ILOpCode.Stind_i -> failwith "todo"
- | ILOpCode.Conv_u -> failwith "todo"
+ | ILOpCode.Conv_u -> IlOp.Nullary NullaryIlOp.Conv_U
| ILOpCode.Arglist -> failwith "todo"
| ILOpCode.Ceq -> IlOp.Nullary NullaryIlOp.Ceq
| ILOpCode.Cgt -> IlOp.Nullary NullaryIlOp.Cgt
| ILOpCode.Cgt_un -> IlOp.Nullary NullaryIlOp.Cgt_un
| ILOpCode.Clt -> IlOp.Nullary NullaryIlOp.Clt
| ILOpCode.Clt_un -> IlOp.Nullary NullaryIlOp.Clt_un
- | ILOpCode.Ldftn -> failwith "todo"
+ | ILOpCode.Ldftn ->
+ IlOp.UnaryMetadataToken (UnaryMetadataTokenIlOp.Ldftn, readMetadataToken &reader)
| ILOpCode.Ldvirtftn -> failwith "todo"
| ILOpCode.Ldarg -> failwith "todo"
| ILOpCode.Ldarga -> failwith "todo"
@@ -387,13 +350,15 @@ module TypeInfo =
| ILOpCode.Ldloc -> failwith "todo"
| ILOpCode.Ldloca -> failwith "todo"
| ILOpCode.Stloc -> IlOp.UnaryConst (UnaryConstIlOp.Stloc (reader.ReadUInt16 ()))
- | ILOpCode.Localloc -> failwith "todo"
+ | ILOpCode.Localloc -> IlOp.Nullary NullaryIlOp.Localloc
| ILOpCode.Endfilter -> IlOp.Nullary NullaryIlOp.Endfilter
| ILOpCode.Unaligned -> failwith "todo"
- | ILOpCode.Volatile -> failwith "todo"
- | ILOpCode.Tail -> failwith "todo"
- | ILOpCode.Initobj -> failwith "todo"
- | ILOpCode.Constrained -> failwith "todo"
+ | ILOpCode.Volatile -> IlOp.Nullary NullaryIlOp.Volatile
+ | ILOpCode.Tail -> IlOp.Nullary NullaryIlOp.Tail
+ | ILOpCode.Initobj ->
+ IlOp.UnaryMetadataToken (UnaryMetadataTokenIlOp.Initobj, readMetadataToken &reader)
+ | ILOpCode.Constrained ->
+ IlOp.UnaryMetadataToken (UnaryMetadataTokenIlOp.Constrained, readMetadataToken &reader)
| ILOpCode.Cpblk -> failwith "todo"
| ILOpCode.Initblk -> failwith "todo"
| ILOpCode.Rethrow -> IlOp.Nullary NullaryIlOp.Rethrow
@@ -404,7 +369,15 @@ module TypeInfo =
readInstructions ((opCode, offset) :: acc)
- readInstructions []
+ let instructions = readInstructions []
+
+ {
+ Instructions = instructions
+ LocalInit = methodBody.LocalVariablesInitialized
+ MaxStackSize = methodBody.MaxStack
+ ExceptionRegions = methodBody.ExceptionRegions
+ }
+ |> Some
let private readMethodParams
(metadata : MetadataReader)
@@ -439,65 +412,23 @@ module TypeInfo =
)
|> ImmutableArray.CreateRange
- let private typeProvider =
- { new ISignatureTypeProvider with
- member this.GetArrayType (elementType : TypeDefn, shape : ArrayShape) : TypeDefn = failwith "TODO"
- member this.GetByReferenceType (elementType : TypeDefn) : TypeDefn = TypeDefn.Byref elementType
-
- member this.GetSZArrayType (elementType : TypeDefn) : TypeDefn =
- TypeDefn.OneDimensionalArrayLowerBoundZero elementType
-
- member this.GetPrimitiveType (elementType : PrimitiveTypeCode) : TypeDefn =
- PrimitiveType.OfEnum elementType |> TypeDefn.PrimitiveType
-
- member this.GetGenericInstantiation
- (generic : TypeDefn, typeArguments : ImmutableArray)
- : TypeDefn
- =
- TypeDefn.GenericInstantiation (generic, typeArguments)
-
- member this.GetTypeFromDefinition
- (reader : MetadataReader, handle : TypeDefinitionHandle, rawTypeKind : byte)
- : TypeDefn
- =
- let handle : EntityHandle = TypeDefinitionHandle.op_Implicit handle
- let typeKind = reader.ResolveSignatureTypeKind (handle, rawTypeKind)
-
- TypeDefn.FromDefinition typeKind
-
- member this.GetTypeFromReference
- (reader : MetadataReader, handle : TypeReferenceHandle, rawTypeKind : byte)
- : TypeDefn
- =
- let handle : EntityHandle = TypeReferenceHandle.op_Implicit handle
- let typeKind = reader.ResolveSignatureTypeKind (handle, rawTypeKind)
- TypeDefn.FromReference typeKind
-
- member this.GetPointerType (typeCode : TypeDefn) : TypeDefn = TypeDefn.Pointer typeCode
-
- member this.GetFunctionPointerType (signature) =
- TypeDefn.FunctionPointer (TypeMethodSignature.make signature)
-
- member this.GetGenericMethodParameter (genericContext, index) = TypeDefn.GenericMethodParameter index
- member this.GetGenericTypeParameter (genericContext, index) = TypeDefn.GenericTypeParameter index
-
- member this.GetModifiedType (modifier, unmodifiedType, isRequired) =
- TypeDefn.Modified (unmodifiedType, modifier, isRequired)
-
- member this.GetPinnedType (elementType) = TypeDefn.Pinned elementType
- member this.GetTypeFromSpecification (reader, genericContext, handle, rawTypeKind) = failwith "todo"
- }
-
let private readMethod
(peReader : PEReader)
(metadataReader : MetadataReader)
(methodHandle : MethodDefinitionHandle)
- : MethodInfo
+ : MethodInfo option
=
let methodDef = metadataReader.GetMethodDefinition methodHandle
let methodName = metadataReader.GetString methodDef.Name
- let methodSig = methodDef.DecodeSignature (typeProvider, ())
+ let methodSig = methodDef.DecodeSignature (TypeDefn.typeProvider, ())
let methodBody = readMethodBody peReader methodDef
+
+ match methodBody with
+ | None ->
+ Console.Error.WriteLine $"[INF] No method body for {metadataReader.GetString methodDef.Name}"
+ None
+ | Some methodBody ->
+
let methodParams = readMethodParams metadataReader (methodDef.GetParameters ())
let methodGenericParams =
@@ -506,12 +437,15 @@ module TypeInfo =
{
Handle = methodHandle
Name = methodName
- Instructions = methodBody
- Locations = methodBody |> List.map (fun (a, b) -> b, a) |> Map.ofList
+ Instructions = methodBody.Instructions
+ Locations = methodBody.Instructions |> List.map (fun (a, b) -> b, a) |> Map.ofList
Parameters = methodParams
Generics = methodGenericParams
Signature = TypeMethodSignature.make methodSig
+ IsPinvokeImpl = methodDef.Attributes.HasFlag MethodAttributes.PinvokeImpl
+ LocalsInit = methodBody.LocalInit
}
+ |> Some
let internal read
(peReader : PEReader)
@@ -522,8 +456,30 @@ module TypeInfo =
let typeDef = metadataReader.GetTypeDefinition (typeHandle)
let methods = typeDef.GetMethods ()
+ let methodImpls =
+ typeDef.GetMethodImplementations ()
+ |> Seq.map (fun handle ->
+ let m = metadataReader.GetMethodImplementation handle
+
+ if not (m.MethodBody.Kind.HasFlag HandleKind.MethodImplementation) then
+ failwith "unexpected kind"
+
+ KeyValuePair (handle, m.MethodBody)
+ )
+ |> ImmutableDictionary.CreateRange
+
{
Namespace = metadataReader.GetString (typeDef.Namespace)
Name = metadataReader.GetString (typeDef.Name)
- Methods = methods |> Seq.map (readMethod peReader metadataReader) |> Seq.toList
+ Methods =
+ methods
+ |> Seq.choose (fun m ->
+ let result = readMethod peReader metadataReader m
+
+ match result with
+ | None -> None
+ | Some x -> Some x
+ )
+ |> Seq.toList
+ MethodImpls = methodImpls
}
diff --git a/WoofWare.PawPrint/WoofWare.PawPrint.fsproj b/WoofWare.PawPrint/WoofWare.PawPrint.fsproj
index d0670e3..3d54a46 100644
--- a/WoofWare.PawPrint/WoofWare.PawPrint.fsproj
+++ b/WoofWare.PawPrint/WoofWare.PawPrint.fsproj
@@ -7,6 +7,7 @@
+